/**
 @file sys_usw_nexthop_ecmp.c

 @date 2009-12-23

 @version v2.0

 The file contains all ecmp related function
*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_error.h"

#include "sys_usw_common.h"
#include "sys_usw_opf.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_l3if.h"
#include "sys_usw_wb_nh.h"
#include "sys_usw_register.h"
#include "sys_usw_dma.h"
#include "sys_usw_rpf_spool.h"
#include "sys_usw_api.h"
#include "drv_api.h"


#define SYS_ECMP_ALLOC_MEM_STEP  4
#define SYS_ECMP_SPM_TBL_BASE_WIDTH 13
#define SYS_ECMP_SPM_ENTRY_NUM 8192


/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
int32
sys_usw_nh_update_ecmp_group(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, uint8 is_create);
int32
sys_usw_nh_set_met_aps_en(uint8 lchip, uint32 nhid, uint8 enable);
int32
_sys_usw_nh_ecmp_clear_dlb_flow(uint8 lchip, void* p_nhdb_param);


#define __fragment_move__
/*
typedef int32 (* vector_traversal_fn)(void* array_data, void* user_data);
typedef void (* ctc_list_del_cb_t) (void* val);
typedef int32 (* ctc_list_cmp_cb_t) (void* val1, void* val2);
*/
STATIC int32 _sys_usw_nh_ecmp_linklist_cmp(sys_nh_info_ecmp_t* val1, sys_nh_info_ecmp_t* val2)
{
    if (val1->ecmp_member_base < val2->ecmp_member_base)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}

STATIC int32 _sys_usw_nh_ecmp_fragment_traverse(sys_nh_info_ecmp_t* val, sys_traverse_t* p_travese)
{
    ctc_linklist_t* p_member_list = (ctc_linklist_t*)p_travese->data;
    uint32 min_offset = p_travese->value1;
    uint32 max_offset = p_travese->value2;
    if (val->hdr.nh_entry_type == SYS_NH_TYPE_ECMP &&
        (val->ecmp_member_base >= min_offset && val->ecmp_member_base < max_offset))
    {
        ctc_listnode_add_sort(p_member_list, val);
    }
    return CTC_E_NONE;
}

STATIC int32 _sys_usw_nh_ecmp_get_dsfwd(uint8 lchip, uint32 nh_id, uint32* dsfwd_offset)
{
    sys_nh_info_dsnh_t nh_info;
    sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));

    CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, nh_id, &nh_info));

    if (DRV_FROM_AT(lchip))
    {
        if ( !nh_info.dsfwd1_valid)
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_dsfwd1_offset(lchip, nh_id, dsfwd_offset, 1, CTC_FEATURE_NEXTHOP));
        }
        else
        {
            *dsfwd_offset = nh_info.dsfwd1_offset;
        }
    }
    else
    {

        if ( !nh_info.dsfwd_valid)
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_dsfwd_offset(lchip, nh_id, dsfwd_offset, 1, CTC_FEATURE_NEXTHOP));
        }
        else
        {
            *dsfwd_offset = nh_info.dsfwd_offset;
        }
    }

    return CTC_E_NONE;
}
    

STATIC int32
_sys_usw_nh_update_ldp_ecmp_member(uint8 lchip,
                                   sys_nh_info_ecmp_t* p_nhdb,
                                   void* p_nh_info, uint8 is_tunnel)
{
    sys_dsecmp_member_t sys_ecmp_member;
    uint8 i = 0;
    uint16 ecmp_group_id = 0;
    sys_nh_info_overlay_t *p_overlay = NULL;
    uint16 mem_idx = 0;
    uint8 write_hw = 0;
    sys_nh_db_srh_t* p_srh_tnl = NULL;
    uint32 dest_logic_port = 0;
    uint32 nhid_vni = 0;
    uint32 dsfwd_offset = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update ecmp Gid:%d\n", p_nhdb->hdr.nh_id);

    if(is_tunnel)
    {
        sys_nh_db_arp_t* p_arp = NULL;
        p_srh_tnl = (sys_nh_db_srh_t*)p_nh_info;
        ecmp_group_id = 0;
        dest_logic_port = p_srh_tnl->ldp;
        p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_srh_tnl->arp_id));
        if (NULL == p_arp)
        {
            return CTC_E_NOT_EXIST;
        }
        CTC_ERROR_RETURN(sys_usw_nh_arp_alloc_dsfwd(lchip, p_arp, &dsfwd_offset));
    }
    else
    {
        p_overlay = (sys_nh_info_overlay_t*)p_nh_info;
        ecmp_group_id = p_overlay->ecmp_gid;
        dest_logic_port = p_overlay->dest_logic_port;
        nhid_vni = p_overlay->nhid;
        dsfwd_offset = DRV_FROM_AT(lchip)? p_overlay->hdr.dsfwd1_offset: p_overlay->hdr.dsfwd_offset;
    }

    for (mem_idx = 0; mem_idx < (p_nhdb->valid_cnt+3)/4; mem_idx++)
    {
        sal_memset(&sys_ecmp_member, 0, sizeof(sys_ecmp_member));
        write_hw = 0;
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_MEMBER,
                                   p_nhdb->ecmp_member_base / 4 + mem_idx, &sys_ecmp_member));

        for (i = 0; i < 4; i++)
        {

            if (sys_ecmp_member.info[i].valid == 0
                || dest_logic_port != sys_ecmp_member.info[i].logic_dest_port)
            {
                continue;
            }
           write_hw = 1;

           SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update ECMP_MEMBER,index:%d i:%d\n", p_nhdb->ecmp_member_base / 4 + mem_idx, i);

            sys_ecmp_member.info[i].valid = 1;
            sys_ecmp_member.info[i].dsfwdptr = dsfwd_offset;
            sys_ecmp_member.info[i].dest_channel = 0;

            sys_ecmp_member.info[i].logic_dest_port = dest_logic_port;

            /* overlay bind with vni*/
            if (nhid_vni && (ecmp_group_id != 0 || (DRV_FROM_AT(lchip) && SYS_NH_OVERLAY_NEW_MODE(lchip))))
            {
                sys_ecmp_member.info[i].nexthop_ptr = p_overlay->hdr.dsnh_offset;
                sys_ecmp_member.info[i].bypass_igs_edit = CTC_FLAG_ISSET(p_overlay->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
                sys_ecmp_member.info[i].nexthop_ext = CTC_FLAG_ISSET(p_overlay->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
            }
            else
            {
                sys_ecmp_member.info[i].nexthop_ptr = 0;
            }

            sys_ecmp_member.info[i].ecmp_gid = ecmp_group_id;

        }
        if (write_hw)
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_MEMBER,
                                                         p_nhdb->ecmp_member_base / 4 + mem_idx, &sys_ecmp_member));
        }
    }

    return CTC_E_NONE;
}


int32
sys_usw_nh_ecmp_add_ref_list(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, void* p_tmp_nh_info)
{
    sys_nh_ref_list_node_t* p_curr = NULL;
    sys_nh_ref_list_node_t* p_nh_ref_list_node = NULL;
    sys_nh_info_ext_t* p_nhinfo_ext = NULL;
    sys_nh_db_srh_t* p_srn_tnl = NULL;
    uint8 find_flag = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (0 == p_nhdb->mem_is_tunnel)
    {
        sys_nh_info_com_t* p_nh_info = (sys_nh_info_com_t*)p_tmp_nh_info;
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_ext_by_nhid(lchip, p_nh_info->hdr.nh_id, &p_nhinfo_ext, 1));
        if (NULL == p_nhinfo_ext)
        {
            return CTC_E_NONE;
        }
        p_curr = p_nhinfo_ext->ecmp_list;
    }
    else
    {
        p_srn_tnl = (sys_nh_db_srh_t*)p_tmp_nh_info;
        p_curr = p_srn_tnl->pd->ecmp_list;
    }

    while (p_curr)
    {
        if ((sys_nh_info_ecmp_t*)p_curr->p_ref_nhinfo == p_nhdb)
        {
            find_flag = 1;
            break;
        }
        p_curr = p_curr->p_next;
    }

    if (1 == find_flag)
    {
        return CTC_E_NONE;
    }


    if (0 == p_nhdb->mem_is_tunnel)
    {
        p_nh_ref_list_node = (sys_nh_ref_list_node_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_ref_list_node_t));
        if (p_nh_ref_list_node == NULL)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            return CTC_E_NO_MEMORY;

        }
        p_nh_ref_list_node->p_ref_nhinfo = (sys_nh_info_com_t*)p_nhdb;
        p_nh_ref_list_node->p_next = p_nhinfo_ext->ecmp_list;

        p_nhinfo_ext->ecmp_list = p_nh_ref_list_node;
    }
    else
    {
        CTC_ERROR_RETURN(_sys_usw_nh_srv6_update_tnl_mem(lchip, (sys_nh_info_com_t*)p_nhdb, (sys_nh_db_srh_t *)p_tmp_nh_info, 1));
    }
    
    return CTC_E_NONE;
}

int32
sys_usw_nh_ecmp_del_ref_list(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, sys_nh_info_com_t* p_tmp_nh_info)
{
    sys_nh_ref_list_node_t* p_curr = NULL;
    sys_nh_ref_list_node_t* p_prev = NULL;
    sys_nh_info_ext_t* p_nhinfo_ext = NULL;
    uint16 index = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if(0 == p_nhdb->mem_is_tunnel)
    {
        sys_nh_info_com_t* p_nh_info = (sys_nh_info_com_t*)p_tmp_nh_info;
        for (index = 0; index < p_nhdb->ecmp_cnt; index++)/*need del member nh from p_nhdb->nh_array before call sys_usw_nh_ecmp_del_ref_list*/
        {
            if (p_nhdb->nh_array[index] == p_nh_info->hdr.nh_id)
            {
                return CTC_E_NONE;
            }
        }

        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_ext_by_nhid(lchip, p_nh_info->hdr.nh_id, &p_nhinfo_ext, 0));
        if (NULL == p_nhinfo_ext)
        {
            return CTC_E_NONE;
        }
        p_curr = p_nhinfo_ext->ecmp_list;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_COM, 1);
        while (p_curr)
        {
            if ((sys_nh_info_ecmp_t*)p_curr->p_ref_nhinfo == p_nhdb)
            {
                if (NULL == p_prev)
                /*Remove first node*/
                {
                    p_nhinfo_ext->ecmp_list = p_curr->p_next;
                }
                else
                {
                    p_prev->p_next = p_curr->p_next;
                }

                mem_free(p_curr);
                CTC_ERROR_RETURN(sys_usw_nh_free_nhinfo_ext_by_nhid(lchip, p_nh_info->hdr.nh_id));
                return CTC_E_NONE;
            }

            p_prev = p_curr;
            p_curr = p_curr->p_next;
        }
    }
    else
    {
        sys_nh_db_srh_t *p_srh_tnl = (sys_nh_db_srh_t *)p_tmp_nh_info;
        for (index = 0; index < p_nhdb->ecmp_cnt; index++)/*need del member nh from p_nhdb->nh_array before call sys_usw_nh_ecmp_del_ref_list*/
        {
            if (p_nhdb->nh_array[index] == p_srh_tnl->srh_id)
            {
                return CTC_E_NONE;
            }
        }
        CTC_ERROR_RETURN(_sys_usw_nh_srv6_update_tnl_mem(lchip, (sys_nh_info_com_t*)p_nhdb, p_srh_tnl, 0));
    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_update_hecmp(uint8 lchip, ctc_nh_ecmp_nh_param_t* p_nh_ecmp_param, sys_nh_info_ecmp_t* p_nhdb, uint8 is_create)
{

    sys_usw_opf_t opf;
    uint32 offset  = 0;
    uint16 index = 0;
    uint16 mem_index = 0;
    int32 ret = 0;
    sys_nh_info_com_t* p_nh_info = NULL;
    uint32 cmd = 0;
    uint32 hecmp_mem[SYS_ECMP_MAX_HECMP_MEM] = {0};
	uint8 tmp_index = 0;

    CTC_MAX_VALUE_CHECK(p_nh_ecmp_param->nh_num, g_usw_nh_master[lchip]->hecmp_mem_num);
    if (p_nh_ecmp_param->stats_id)
    {
        return CTC_E_NOT_SUPPORT;
    }

    if (is_create)
    {
        p_nhdb->nh_array = (uint32*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(uint32)*g_usw_nh_master[lchip]->hecmp_mem_num);
        if (!p_nhdb->nh_array)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_nhdb->nh_array, 0, sizeof(uint32)*g_usw_nh_master[lchip]->hecmp_mem_num);
        sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_group_opf_type;
        opf.pool_index = 0;
        opf.reverse    = 1;

        CTC_ERROR_GOTO(sys_usw_opf_alloc_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, g_usw_nh_master[lchip]->hecmp_mem_num, &offset), ret, error_proc);
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] H-ECMP member base:%u! \n", offset);
        p_nhdb->ecmp_group_id = offset;
        p_nhdb->valid_cnt = p_nh_ecmp_param->nh_num;
        p_nhdb->ecmp_cnt = p_nhdb->valid_cnt;
        p_nhdb->mem_num = g_usw_nh_master[lchip]->hecmp_mem_num;
        for (index = 0; index < g_usw_nh_master[lchip]->hecmp_mem_num && p_nh_ecmp_param->nh_num; index++)
        {
            mem_index = (index%p_nh_ecmp_param->nh_num);
            hecmp_mem[index] = p_nh_ecmp_param->nhid[mem_index];
            p_nhdb->nh_array[index] = hecmp_mem[index];
        }

        for (index = 0; index < p_nhdb->valid_cnt; index++)
        {
            tmp_index = index;
            CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[index], (sys_nh_info_com_t**)&p_nh_info), ret, error_proc);
            if (p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_ECMP)
            {
                ret = CTC_E_INVALID_PARAM;
                goto error_proc;
            }
            CTC_ERROR_GOTO(sys_usw_nh_ecmp_add_ref_list(lchip, p_nhdb, p_nh_info), ret, error_proc);
        }
    }
    else
    {
        /*update*/
        if (p_nh_ecmp_param->upd_type == CTC_NH_ECMP_ADD_MEMBER)
        {
            uint16 max_index = (0 == p_nhdb->valid_cnt) ? g_usw_nh_master[lchip]->hecmp_mem_num:p_nh_ecmp_param->nh_num;
            /*Add*/
            if (p_nhdb->valid_cnt + p_nh_ecmp_param->nh_num > g_usw_nh_master[lchip]->hecmp_mem_num)
            {
                return CTC_E_INVALID_PARAM;
            }
            for (index = 0; index <  max_index; index++)
            {
                mem_index = index%p_nh_ecmp_param->nh_num;
                p_nhdb->nh_array[index+p_nhdb->valid_cnt] = p_nh_ecmp_param->nhid[mem_index];
                CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[mem_index], (sys_nh_info_com_t**)&p_nh_info), ret, error_proc);
                if (p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_ECMP)
                {
                    ret = CTC_E_INVALID_PARAM;
                    goto error_proc;
                }
                CTC_ERROR_GOTO(sys_usw_nh_ecmp_add_ref_list(lchip, p_nhdb, p_nh_info), ret, error_proc);
            }
            p_nhdb->valid_cnt += p_nh_ecmp_param->nh_num;
            p_nhdb->ecmp_cnt = p_nhdb->valid_cnt;
        }
        else
        {
            /*Del*/
            if (p_nh_ecmp_param->nh_num > p_nhdb->valid_cnt)
            {
                return CTC_E_INVALID_PARAM;
            }

            for (index = 0; index < p_nhdb->ecmp_cnt; index++)
            {
                if (p_nh_ecmp_param->nhid[0] == p_nhdb->nh_array[index])
                {
                    break;
                }
            }
            p_nhdb->nh_array[index] = p_nhdb->nh_array[p_nhdb->valid_cnt-1];
            p_nhdb->valid_cnt--;
            p_nhdb->ecmp_cnt = p_nhdb->valid_cnt;
            CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[0], (sys_nh_info_com_t**)&p_nh_info));
            CTC_ERROR_RETURN(sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info));
        }

        for (index = 0; index < g_usw_nh_master[lchip]->hecmp_mem_num && p_nhdb->valid_cnt; index++)
        {
            mem_index = (index%p_nhdb->valid_cnt);
            hecmp_mem[index] = p_nhdb->nh_array[mem_index];
            p_nhdb->nh_array[index] = hecmp_mem[index];
        }
    }

    for (index = 0; index < g_usw_nh_master[lchip]->hecmp_mem_num; index++)
    {
        sys_nh_info_ecmp_t* p_mem_nh = NULL;
        DsEcmpGroup_m ecmp_grp;

        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] H-ECMP member nhid:%u index:%u\n", hecmp_mem[index], index);
        sal_memset(&ecmp_grp, 0, sizeof(DsEcmpGroup_m));
        if (!p_nhdb->valid_cnt)
        {
            SetDsEcmpGroup(V, memberNum_f, &ecmp_grp, 0);
            SetDsEcmpGroup(V, memberPtrBase_f, &ecmp_grp, 0);
            cmd = DRV_IOW(DsEcmpGroup_t, DRV_ENTRY_FLAG);
            CTC_ERROR_GOTO(DRV_IOCTL(lchip, (p_nhdb->ecmp_group_id+index), cmd, &ecmp_grp), ret, error_proc);
        }
        else
        {
            ret = sys_usw_nh_get_nhinfo_by_nhid(lchip, hecmp_mem[index], (sys_nh_info_com_t**)&p_nh_info);
            if (ret == CTC_E_NOT_EXIST)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] H-ECMP member not exist, nhid:%u index:%u\n", hecmp_mem[index], index);
                continue;
            }
            else if (ret)
            {
                goto error_proc;
            }

            if (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_ECMP)
            {
                p_mem_nh = (sys_nh_info_ecmp_t*)p_nh_info;
                cmd = DRV_IOR(DsEcmpGroup_t, DRV_ENTRY_FLAG);
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, p_mem_nh->ecmp_group_id, cmd, &ecmp_grp), ret, error_proc);
                cmd = DRV_IOW(DsEcmpGroup_t, DRV_ENTRY_FLAG);
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, (p_nhdb->ecmp_group_id+index), cmd, &ecmp_grp), ret, error_proc);
            }
        }
    }

    p_nhdb->h_ecmp_en = 1;
    return CTC_E_NONE;
error_proc:
    if (is_create)
    {
        sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, g_usw_nh_master[lchip]->hecmp_mem_num, offset);
        for (index = 0; index < tmp_index; index++)
        {
            CTC_ERROR_DUMP(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[index], (sys_nh_info_com_t**)&p_nh_info));
            p_nhdb->nh_array[index] = 0;
            CTC_ERROR_DUMP(sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info));
        }
        p_nhdb->valid_cnt = 0;
        p_nhdb->ecmp_cnt = 0;
        p_nhdb->mem_num = 0;
        mem_free(p_nhdb->nh_array);
    }
    return ret;
}

STATIC int32
_sys_usw_nh_update_hecmp_member(uint8 lchip, uint32 mem_nhid, uint8 is_del)
{
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_info_ext_t* p_nh_info_ext = NULL;
    sys_nh_ref_list_node_t* p_curr = NULL;
    sys_nh_ref_list_node_t* p_next = NULL;
    sys_nh_info_ecmp_t* p_hecmp_nh = NULL;
    sys_nh_info_ecmp_t* p_mem_nh = NULL;
    uint16 index = 0;
    uint32 cmd = 0;
    DsEcmpGroup_m ecmp_grp;
    ctc_nh_ecmp_nh_param_t ecmp_nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, mem_nhid, (sys_nh_info_com_t**)&p_nh_info));
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_ext_by_nhid(lchip, mem_nhid, &p_nh_info_ext, 0));
    if (NULL == p_nh_info_ext)
    {
        return CTC_E_NONE;
    }
    p_curr = p_nh_info_ext->ecmp_list;
    p_mem_nh = (sys_nh_info_ecmp_t*)p_nh_info;
    while (p_curr)
    {
        /*the p curr node maybe freed, so need to save the next node*/
        p_next = p_curr->p_next;
        p_hecmp_nh = (sys_nh_info_ecmp_t*)p_curr->p_ref_nhinfo;
        for (index = 0; index < g_usw_nh_master[lchip]->hecmp_mem_num; index++)
        {
            if (p_hecmp_nh->nh_array[index] != mem_nhid)
            {
                continue;
            }
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] Find H-Ecmp member, index:%u, mem_nh:%u! \n", index, mem_nhid);

            if (is_del)
            {
                sal_memset(&ecmp_nh_param, 0, sizeof(ctc_nh_ecmp_nh_param_t));
                ecmp_nh_param.upd_type = CTC_NH_ECMP_REMOVE_MEMBER;
                ecmp_nh_param.nh_num = 1;
                ecmp_nh_param.nhid[0] = mem_nhid;
                _sys_usw_nh_update_hecmp(lchip,&ecmp_nh_param,p_hecmp_nh, 0);
            }
            else
            {
                cmd = DRV_IOR(DsEcmpGroup_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_mem_nh->ecmp_group_id, cmd, &ecmp_grp));
                cmd = DRV_IOW(DsEcmpGroup_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, (p_hecmp_nh->ecmp_group_id+index), cmd, &ecmp_grp));
            }
        }
        p_curr = p_next;
    }

    return CTC_E_NONE;
}

int32 sys_usw_nh_ecmp_fragment(uint8 lchip, uint8 opf_pool_index)
{
    int32  ret = CTC_E_NONE;
    int32  free_length;
    uint8  find;
    uint16 alloc_member_num = 0;
    uint16 first_alloc_member_num = 0;
    sys_usw_opf_t opf;
    sys_nh_info_ecmp_t* first_group = NULL;
    sys_nh_info_ecmp_t* next_group = NULL;
    sys_nh_info_ecmp_t* find_group = NULL;
    ctc_listnode_t* f_node;
    ctc_listnode_t* node;
    ctc_linklist_t* p_member_list = ctc_list_create((ctc_list_cmp_cb_t)_sys_usw_nh_ecmp_linklist_cmp, NULL);
    sys_traverse_t  traveser_data;

    if(!p_member_list)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(&opf, 0, sizeof(opf));
    sal_memset(&traveser_data, 0, sizeof(traveser_data));

    traveser_data.data = p_member_list;

    if(g_usw_nh_master[lchip]->h_ecmp_en && DRV_FROM_TMM(lchip))
    {
        traveser_data.value1 = opf_pool_index ? 0 : MCHIP_CAP(SYS_CAP_NH_ECMP_MEMBER_NUM)/2;
        traveser_data.value2 = opf_pool_index ? MCHIP_CAP(SYS_CAP_NH_ECMP_MEMBER_NUM)/2:MCHIP_CAP(SYS_CAP_NH_ECMP_MEMBER_NUM);
    }
    else
    {
        traveser_data.value1 = 0;
        traveser_data.value2 = MCHIP_CAP(SYS_CAP_NH_ECMP_MEMBER_NUM);
    }

     /* vector traverse;*/
    CTC_ERROR_GOTO(ctc_hash_traverse(g_usw_nh_master[lchip]->nhid_hash, \
                                (hash_traversal_fn)_sys_usw_nh_ecmp_fragment_traverse, &traveser_data), ret, error_proc);

    for(f_node = p_member_list->head; f_node && f_node->next; f_node = f_node->next)
    {
        next_group = (sys_nh_info_ecmp_t*)f_node->next->data;
        first_group = f_node->data;
        first_alloc_member_num = (first_group->mem_num+SYS_ECMP_ALLOC_MEM_STEP-1)/SYS_ECMP_ALLOC_MEM_STEP*SYS_ECMP_ALLOC_MEM_STEP;
        free_length = next_group->ecmp_member_base - first_group->ecmp_member_base - first_alloc_member_num;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "first group info:\n");
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n","tid", first_group->ecmp_group_id);
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n","max member num", first_group->mem_num);
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n","member base", first_group->ecmp_member_base);

        if (free_length == 0)
        {
            continue;
        }
        else if(free_length < 0)
        {
            ret = CTC_E_UNEXPECT;
            goto error_proc;
        }

        while (1)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n","------free_length  ", free_length);
             /*double check for while*/
            if (free_length <= 0)
            {
                break;
            }

            find = 0;
            for (node = p_member_list->tail; node; node = node->prev)
            {
                if (node == f_node)
                {
                    break;
                }
                find_group = (sys_nh_info_ecmp_t*)node->data;
                alloc_member_num = (find_group->mem_num + SYS_ECMP_ALLOC_MEM_STEP - 1) / SYS_ECMP_ALLOC_MEM_STEP*SYS_ECMP_ALLOC_MEM_STEP;

                if ((find_group->type != CTC_NH_ECMP_TYPE_DLB) && (find_group->type != CTC_NH_ECMP_TYPE_SPRAY) && (find_group->type != CTC_NH_ECMP_TYPE_XERSPAN) &&
                       (alloc_member_num == free_length) && (find_group->ecmp_member_base > first_group->ecmp_member_base))
                {
                    find = 1;
                    break;
                }
            }

            if (find)
            {
                 /* first update  hardware*/
               uint16 mem_entry_idx = 0;
                uint16 mem_entry_num = 0;
                DsEcmpMember_m member;
                DsEcmpGroup_m  group;

                uint16 new_member_base = first_group->ecmp_member_base + first_alloc_member_num;
                uint32 cmdr = DRV_IOR(DsEcmpMember_t, DRV_ENTRY_FLAG);
                uint32 cmdw = DRV_IOW(DsEcmpMember_t, DRV_ENTRY_FLAG);

                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "The find group info:\n");
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n", "tid", find_group->ecmp_group_id);
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n", "max member num",find_group->mem_num);
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "      %10s: %-10d\n", "member base", find_group->ecmp_member_base);

                mem_entry_num = (find_group->mem_num + SYS_ECMP_MEM_HW_SUB_NUM - 1) / SYS_ECMP_MEM_HW_SUB_NUM;
                for (mem_entry_idx = 0; mem_entry_idx < mem_entry_num; mem_entry_idx++)
                {
                   CTC_ERROR_GOTO(DRV_IOCTL(lchip, find_group->ecmp_member_base / 4 + mem_entry_idx, cmdr, &member), ret, error_proc);
                    CTC_ERROR_GOTO(DRV_IOCTL(lchip, new_member_base / 4 + mem_entry_idx, cmdw, &member), ret, error_proc);
                }

                cmdr = DRV_IOR(DsEcmpGroup_t, DRV_ENTRY_FLAG);
                cmdw = DRV_IOW(DsEcmpGroup_t, DRV_ENTRY_FLAG);

                CTC_ERROR_GOTO(DRV_IOCTL(lchip, find_group->ecmp_group_id, cmdr, &group), ret, error_proc);
                SetDsEcmpGroup(V, memberPtrBase_f, &group, new_member_base / 4);
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, find_group->ecmp_group_id, cmdw, &group), ret, error_proc);

                opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
                opf.multiple = SYS_ECMP_MEM_HW_SUB_NUM;
                opf.pool_index = opf_pool_index;
                opf.reverse    = 0;

                CTC_ERROR_GOTO(sys_usw_opf_free_offset(lchip, &opf, find_group->mem_num, (uint32)find_group->ecmp_member_base), ret, error_proc);
                CTC_ERROR_GOTO(sys_usw_opf_alloc_offset_from_position(lchip, &opf, find_group->mem_num, new_member_base), ret, error_proc);

                find_group->ecmp_member_base = new_member_base;
                ctc_listnode_delete_node(p_member_list, node);
                ctc_listnode_add_sort(p_member_list, find_group);
                break;
            }
            else
            {
                free_length -= SYS_ECMP_MEM_HW_SUB_NUM;
            }
        }
    }

 error_proc:
    ctc_list_delete(p_member_list);
    return ret;
}

int32
_sys_usw_nh_ecmp_clear_ant_flow(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, uint32 nh_id, uint8 is_all)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 index = 0;
    uint32 value = 0;
    uint32 base = p_nhdb->ant_flow_base << SYS_ECMP_SPM_TBL_BASE_WIDTH;
    sys_fwd_t dsfwd;
    sys_nh_info_com_t* p_nh_info = NULL;
    uint32 dest_channel = 0;
    DsAntFlowEcmp_m antflow_ecmp;

    if (!p_nhdb->ant_flow_en)
    {
        return CTC_E_NONE;
    }

    if (is_all)
    {
        sys_dma_tbl_rw_t dma_rw;
        drv_work_platform_type_t platform_type;
        uint32 wr_size = 0;
        uint8 chan_en = 0;
        sal_memset(&dma_rw, 0, sizeof(dma_rw));
        drv_get_platform_type(lchip, &platform_type);
        sys_usw_dma_get_chan_en(lchip, SYS_DMA_TBL_WR_CHAN_ID, &chan_en);
        if ((platform_type == HW_PLATFORM) && chan_en)
        {
            /*clear by dma */
            dma_rw.entry_len = DRV_TABLE_ENTRY_SIZE(lchip, DsAntFlowEcmp_t);
            dma_rw.entry_num = SYS_ECMP_SPM_ENTRY_NUM;
            wr_size = dma_rw.entry_num * dma_rw.entry_len;
            MALLOC_ZERO(MEM_NEXTHOP_MODULE, dma_rw.buffer, wr_size);
            if (NULL == dma_rw.buffer)
            {
                return CTC_E_NO_MEMORY;
            }
            drv_usw_table_get_hw_addr(lchip, DsAntFlowEcmp_t, base, &dma_rw.tbl_addr, FALSE);
            dma_rw.entry_offset = TABLE_ENTRY_OFFSET(lchip, DsAntFlowEcmp_t);
            ret = MCHIP_DMA(lchip)->dma_write_table(lchip, &dma_rw);
            mem_free(dma_rw.buffer);
        }
        else
        {
            sal_memset(&antflow_ecmp, 0, sizeof(antflow_ecmp));
            cmd = DRV_IOW(DsAntFlowEcmp_t, DRV_ENTRY_FLAG);
            for (index = 0; index < SYS_ECMP_SPM_ENTRY_NUM; index++)
            {
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, base + index, cmd, &antflow_ecmp));
            }
        }
    }
    else
    {
        uint16 lport = 0;
        uint8 gchip_id = 0;
        uint32 dsfwd_offset = 0;
        sys_usw_dmps_port_info_t dmps_port_info = {0};

        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, nh_id, (sys_nh_info_com_t**)&p_nh_info));
        dsfwd_offset = DRV_FROM_AT(lchip)?p_nh_info->hdr.dsfwd1_offset:p_nh_info->hdr.dsfwd_offset;
        CTC_ERROR_RETURN(sys_usw_nh_get_entry_dsfwd(lchip, dsfwd_offset, (void*)&dsfwd, DRV_FROM_AT(lchip)));
        if (!((CTC_IS_BIT_SET(dsfwd.dest_map, 18))/*mcast*/
            || SYS_DESTMAP_IS_CPU(dsfwd.dest_map)/*to cpu*/
            || SYS_DESTMAP_IS_PROFILE(dsfwd.dest_map)
            || (0x1F == SYS_DECODE_DESTMAP_GCHIP(dsfwd.dest_map))
            || (FALSE == sys_usw_chip_is_local(lchip, SYS_DECODE_DESTMAP_GCHIP(dsfwd.dest_map)))))
        {
            lport = dsfwd.dest_map&0x1FF;
            sys_usw_get_gchip_id( lchip, &gchip_id);
            dmps_port_info.gport = CTC_MAP_LPORT_TO_GPORT(gchip_id, lport);
            CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_CHAN_ID, &dest_channel));
            if ((DRV_FROM_TMM(lchip)) && (SYS_DMPS_INVALID_CHAN_ID != dest_channel))
            {
                value = 0;
                cmd = DRV_IOW(DsChannelToEcmpGroupMap_t, DsChannelToEcmpGroupMap_ecmpGroupId_f);
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, dest_channel, cmd, &value));
            }
        }
    }
    return ret;
}

int32
_sys_usw_nh_ecmp_clear_dlb_flow(uint8 lchip, void* p_nhdb_param)
{
    sys_dma_tbl_rw_t dma_rw;
    drv_work_platform_type_t platform_type;
    sys_nh_info_ecmp_t* p_nhdb = (sys_nh_info_ecmp_t* )p_nhdb_param;
    DsDlbFlowStateLeft_m* p_dlb_flow_left;
    uint32 tbl_id[2] = {DsDlbFlowStateLeft_t, DsDlbFlowStateRight_t};
    uint32 cmd = 0;
    uint16 loop1 = 0;
    uint16 loop2 = 0;

    drv_get_platform_type(lchip, &platform_type);
    if (platform_type != HW_PLATFORM)
    {
        return CTC_E_NONE;
    }
    /*left & right*/
    for(loop1 = 0; loop1 < 2; loop1++)
    {
        sal_memset(&dma_rw, 0, sizeof(sys_dma_tbl_rw_t));
        dma_rw.entry_len = TABLE_ENTRY_SIZE(lchip, tbl_id[loop1]);
        dma_rw.entry_num = TABLE_MAX_INDEX(lchip, tbl_id[loop1]);
        dma_rw.entry_offset = TABLE_ENTRY_OFFSET(lchip, tbl_id[loop1]);
        MALLOC_ZERO(MEM_NEXTHOP_MODULE, dma_rw.buffer, dma_rw.entry_len*dma_rw.entry_num);
        if (NULL == dma_rw.buffer)
        {
            return CTC_E_NO_MEMORY;
        }

        drv_usw_table_get_hw_addr(lchip, tbl_id[loop1], 0, &dma_rw.tbl_addr, FALSE);
        MCHIP_DMA(lchip)->dma_read_table(lchip, &dma_rw);
        cmd = DRV_IOW(tbl_id[loop1], DRV_ENTRY_FLAG);
        for (loop2 = 0; loop2 < dma_rw.entry_num; loop2++)
        {
            p_dlb_flow_left = (DsDlbFlowStateLeft_m *)dma_rw.buffer + loop2;
            if(((GetDsDlbFlowStateLeft(V, hashKey_f, p_dlb_flow_left) >> 10) & 0x3FF) == p_nhdb->ecmp_group_id)
            {
                SetDsDlbFlowStateLeft(V, valid_f, p_dlb_flow_left, 0);
                DRV_IOCTL(lchip, loop2, cmd, p_dlb_flow_left);
            }
        }
        mem_free(dma_rw.buffer);
    }
    return CTC_E_NONE;
}

int32
sys_usw_nh_update_xerspan_group(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb)
{
    uint16 index = 0;
    uint32 nhid = 0;
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_info_ip_tunnel_t* p_tunnel_nhdb = NULL;
    ds0_t ds;
    sys_nexthop_t dsnh_8w;
    uint16 i = 0;
    uint16 hash_num = 0;
    uint16 mem_cnt = 0;
    uint32 dsnh_offset = 0;
    uint32 l3edit_type = 0;

    for (i = 7; i >= 1; i--)
    {
        if ((p_nhdb->valid_cnt <= (1 << i)) && (p_nhdb->valid_cnt > (1 << (i - 1))))
        {
            break;
        }
    }

    mem_cnt =  (p_nhdb->valid_cnt > 2)?((1 << i)):p_nhdb->valid_cnt ;
    hash_num = (p_nhdb->valid_cnt > 2)?i: ((p_nhdb->valid_cnt == 2)?1:0);


    for (index = 0 ; index < mem_cnt; index++)
    {
        i  = (index < p_nhdb->valid_cnt )?index:(index - p_nhdb->valid_cnt);
        nhid =  p_nhdb->nh_array[i];
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Update nhid:%d\n", nhid);

        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_info));

        p_tunnel_nhdb = (sys_nh_info_ip_tunnel_t *)p_nh_info;
        if ((CTC_FLAG_ISSET(p_tunnel_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))&&(p_tunnel_nhdb->outer_l2_edit_offset))
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, (p_tunnel_nhdb->outer_l2_edit_offset), ds));

            if(((p_tunnel_nhdb->outer_l2_edit_offset) % 2) == 1)
            {
                sal_memcpy(ds, (uint8*)ds + DRV_TABLE_ENTRY_SIZE(lchip, DsL2Edit3WOuter_t), DRV_TABLE_ENTRY_SIZE(lchip, DsL2Edit3WOuter_t));
            }

            /*TBD*/
            CTC_ERROR_RETURN(sys_usw_nh_set_asic_table(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, (p_nhdb->l2edit_offset_base + index*4) , ds));
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "l2edit_offset = read:  0x%x, write: 0x%x \n", p_tunnel_nhdb->outer_l2_edit_offset, p_nhdb->l2edit_offset_base + index*4);
        }

        if (CTC_FLAG_ISSET(p_tunnel_nhdb->flag, SYS_NH_IP_TUNNEL_FLAG_IN_V6))
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6 + SYS_NH_TYPE_STEP_TO_INNER, p_tunnel_nhdb->dsl3edit_offset, ds));
        }
        else
        {
            l3edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V4;
            if (DRV_FROM_TMM(lchip))
            {
                l3edit_type = p_tunnel_nhdb->is_12w? SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V4_4X : SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V4;
            }
            CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip, l3edit_type + SYS_NH_TYPE_STEP_TO_INNER, p_tunnel_nhdb->dsl3edit_offset, ds));
        }
        CTC_ERROR_RETURN(sys_usw_nh_set_asic_table(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6 + SYS_NH_TYPE_STEP_TO_INNER, p_nhdb->l3edit_offset_base + index*4, ds));
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "l3edit_offset = read:  0x%x, write: 0x%x \n",  p_tunnel_nhdb->dsl3edit_offset, p_nhdb->l3edit_offset_base + index*4);
    }

    dsnh_offset = p_nhdb->hdr.dsnh_offset;
    dsnh_8w.offset = dsnh_offset;
    dsnh_8w.hash_num =hash_num;
    dsnh_8w.update_type = SYS_NH_UPDATE_TYPE_HASH_NUM;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "dsnh_offset = %d, hash_cnt:%d Valid edit_num = %d\n", dsnh_offset, hash_num, p_nhdb->valid_cnt);
    CTC_ERROR_RETURN(sys_usw_nh_update_asic_table(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_8W, dsnh_offset, &dsnh_8w));

    return CTC_E_NONE;

}

int32
_sys_usw_nh_update_ecmp_member(uint8 lchip,sys_nh_info_ecmp_t* p_nhdb,uint8 change_type,
                                  uint16 mem_idx,
                                  uint16 member_num,
                                 uint16 max_ecmp,
                                 uint32 nhid)
{

    uint16 loop, loop2 = 0;

    uint16 move_num = 0;
    uint32 *move_mem_array;

    move_mem_array = mem_malloc(MEM_NEXTHOP_MODULE, max_ecmp * sizeof(uint32));
    if(!move_mem_array)
    {
      SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update_ecmp_member nhid:%d failed\n", nhid);
      return CTC_E_NO_MEMORY;
    }

    switch (change_type)
    {
        case SYS_NH_CHANGE_TYPE_FWD_TO_UNROV:
            if (mem_idx < p_nhdb->valid_cnt)
            {
                for (loop = 0,loop2 =0; loop < p_nhdb->valid_cnt; loop++)
                {/*find valid member*/
                    if (p_nhdb->nh_array[loop] != nhid)
                    {
                        move_mem_array[loop2++] = p_nhdb->nh_array[loop];
                    }
                }
                move_num = p_nhdb->valid_cnt - member_num;

                for (loop = 0,loop2 =0; loop < p_nhdb->valid_cnt; loop++)
                {
                    if (loop < move_num )
                        p_nhdb->nh_array[loop] = move_mem_array[loop2++];
                    else
                        p_nhdb->nh_array[loop]  =  nhid;

                }
                p_nhdb->valid_cnt -= member_num;
            }

            break;

        case SYS_NH_CHANGE_TYPE_UNROV_TO_FWD:
        case SYS_NH_CHANGE_TYPE_ADD_DYNTBL:
            if (mem_idx >= p_nhdb->valid_cnt)
            {
                for (loop = p_nhdb->valid_cnt,loop2 =0; loop < p_nhdb->ecmp_cnt; loop++)
                {
                    if (p_nhdb->nh_array[loop]  != nhid)
                    {/*find invalid member*/
                        move_mem_array[loop2++] = p_nhdb->nh_array[loop];
                    }
                }
                for (loop = p_nhdb->valid_cnt, loop2 = 0; loop < p_nhdb->ecmp_cnt; loop++)
                {
                    if (loop < (p_nhdb->valid_cnt + member_num) )
                        p_nhdb->nh_array[loop] =  nhid;
                    else
                        p_nhdb->nh_array[loop] = move_mem_array[loop2++];

                }
                p_nhdb->valid_cnt += member_num;
            }


            break;

        case SYS_NH_CHANGE_TYPE_NH_DELETE:
            for (loop = 0,loop2= 0; loop < p_nhdb->ecmp_cnt; loop++)
            {
                if (p_nhdb->nh_array[loop] != nhid)
                {
                    move_mem_array[loop2++] = p_nhdb->nh_array[loop];
                }
            }
            for (loop = 0,loop2 =0; loop < (p_nhdb->ecmp_cnt - member_num); loop++)
            {
                p_nhdb->nh_array[loop] = move_mem_array[loop2++];
            }
            if (mem_idx < p_nhdb->valid_cnt)
            {
                p_nhdb->valid_cnt -= member_num ;
            }
            p_nhdb->ecmp_cnt -= member_num;
            break;

        case SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR:
            break;

    }

    mem_free(move_mem_array);

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_ecmp_member(uint8 lchip, uint32 nhid, uint8 change_type, sys_nh_ref_list_node_t* ecmp_list)
{
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_info_ecmp_t* p_nhdb = NULL;
    uint16 ecmp_mem_idx = 0, member_num = 0;
    sys_nh_ref_list_node_t* p_curr = NULL;
    sys_nh_info_dsnh_t nh_info;
    uint16 loop = 0;
    uint16 max_ecmp = 0;
    sys_nh_db_srh_t* p_srh_tnl = NULL;
    uint8 is_tunnel = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    is_tunnel = (change_type == SYS_NH_CHANGE_TYPE_UPDATE_SRH)?1:0;

    if (0 == is_tunnel)
    {
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, nhid, &nh_info));
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_info));
    }
    else
    {
        p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, nhid);
        if (NULL == p_srh_tnl)
        {
            return CTC_E_NOT_EXIST;
        }
    }
    p_curr = ecmp_list;
    
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP_MEM, 1);

    while (p_curr)
    {
        member_num = 0;
        ecmp_mem_idx = 0;
        p_nhdb = (sys_nh_info_ecmp_t*)p_curr->p_ref_nhinfo;
      /*
           When ecmp mem >MCHIP_CAP(SYS_CAP_NH_MAX_ECPN),ecmp  member can't update.(Only for replace ecmp)
           System use  replace ecmp guide:
           1. Call  replace ecmp;
           2. Call fwd -> unrsv
       */
        if (!p_nhdb || !p_nhdb->nh_array || p_nhdb->valid_cnt > MCHIP_CAP(SYS_CAP_NH_MAX_ECPN) )
        {
            p_curr = p_curr->p_next;
            continue;
        }

        for (loop = 0; loop < p_nhdb->ecmp_cnt; loop++)
        {
            if (p_nhdb->nh_array[loop] == nhid)
            {
                member_num ++;
                ecmp_mem_idx = loop;
            }
        }

        max_ecmp = p_nhdb->mem_num;

        if (member_num == 0)
        {
            p_curr = p_curr->p_next;
            continue;
        }

        if ((change_type == SYS_NH_CHANGE_TYPE_UPDATE_LDP && p_nhdb->h_ecmp_en)
            || (change_type == SYS_NH_CHANGE_TYPE_UPDATE_SRH))

        {
            _sys_usw_nh_update_ldp_ecmp_member(lchip, p_nhdb, is_tunnel?(void*)p_srh_tnl:(void*)p_nh_info, is_tunnel);
            p_curr = p_curr->p_next;
            continue;
        }

        if ((SYS_MAP_CTC_GPORT_TO_GCHIP(nh_info.gport) == 0x1f ||  CTC_IS_CPU_PORT(nh_info.gport) ||
            (FALSE == sys_usw_chip_is_local(lchip, CTC_MAP_GPORT_TO_GCHIP(nh_info.gport))))
            && (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY || p_nhdb->failover_en || p_nhdb->ant_flow_en))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop]Ecmp Dlb member cannot support linkagg \n");
            return CTC_E_INVALID_CONFIG;
        }
         _sys_usw_nh_update_ecmp_member( lchip, p_nhdb, change_type,
                                              ecmp_mem_idx, member_num, max_ecmp, nhid);
        if (p_nhdb->type != CTC_NH_ECMP_TYPE_XERSPAN)
        {
            CTC_ERROR_RETURN(sys_usw_nh_update_ecmp_group(lchip, p_nhdb, 0));
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_update_xerspan_group(lchip, p_nhdb));
        }

        if ((SYS_NH_CHANGE_TYPE_FWD_TO_UNROV == change_type)
            || (SYS_NH_CHANGE_TYPE_NH_DELETE == change_type))
        {
            _sys_usw_nh_ecmp_clear_ant_flow(lchip, p_nhdb, nhid, 0);
        }

        p_curr = p_curr->p_next;
    }

    sys_usw_nh_set_met_aps_en(lchip, nhid, (SYS_NH_CHANGE_TYPE_NH_DELETE != change_type)?1:0);

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_ecmp_group(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, uint8 is_create)
{
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_info_overlay_t *p_overlay = NULL;
    sys_nh_info_srv6_t * p_srv6 = NULL;
    uint16 ecmp_mem_idx = 0;
    uint16 i = 0;
    uint32 dest_channel = 0;
    uint16 max_ecmp = 0;
    uint32 ecmp_mem_id = 0;
    sys_dsecmp_member_t sys_ecmp_member;
    sys_dsecmp_group_t sys_ecmp_group;
    uint16 ecmp_group_id = 0;
    uint32 cmd = 0;
    uint32 field_val = 0;
    uint32 dsfwd_offset = 0;
    uint8 use_dsnh_offset=0;
    sys_usw_dmps_port_info_t dmps_port_info = {0};
    sys_nh_info_dsnh_t dsnh_info;
    sys_rpf_info_t rpf_info = {0};
    uint16 valid_cnt = 0;
    uint32 tmp_gport = 0;
    uint32 logic_dest_port = 0;
    uint8 nh_ptr_valid = 0;
    uint32 nh_ptr = 0;
    uint8 bypass_igs_edit = 0;
    uint8 nh_ext = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if ((p_nhdb->failover_en + (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB) + (p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY) + p_nhdb->ant_flow_en) > 1)
    {
       SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
       return CTC_E_NOT_SUPPORT;
    }

    sal_memset(&sys_ecmp_member, 0, sizeof(sys_ecmp_member));
    sal_memset(&sys_ecmp_group, 0, sizeof(sys_ecmp_group));
    sal_memset(&rpf_info, 0, sizeof(rpf_info));

    CTC_ERROR_RETURN(_sys_usw_nh_get_max_ecmp(lchip, &max_ecmp));
    sal_memset(&dsnh_info, 0, sizeof(sys_nh_info_dsnh_t));
    valid_cnt = p_nhdb->valid_cnt?p_nhdb->valid_cnt:1;
    for (ecmp_mem_idx = 0; ecmp_mem_idx < valid_cnt; ecmp_mem_idx++)
    {
        nh_ptr_valid = 0;
        dsfwd_offset = 0;
        logic_dest_port = 0;
        ecmp_group_id = 0;

        if (p_nhdb->valid_cnt == 0)
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, CTC_NH_RESERVED_NHID_FOR_DROP, (sys_nh_info_com_t**)&p_nh_info));
            _sys_usw_nh_get_nhinfo(lchip, CTC_NH_RESERVED_NHID_FOR_DROP, &dsnh_info);
            dsfwd_offset = DRV_FROM_AT(lchip)? p_nh_info->hdr.dsfwd1_offset : p_nh_info->hdr.dsfwd_offset;
            tmp_gport = dsnh_info.gport;
        }
        else if (!p_nhdb->mem_is_tunnel)
        {
            ecmp_mem_id = ecmp_mem_idx % (p_nhdb->valid_cnt);
            CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nhdb->nh_array[ecmp_mem_id], (sys_nh_info_com_t**)&p_nh_info));
            _sys_usw_nh_get_nhinfo(lchip, p_nhdb->nh_array[ecmp_mem_id], &dsnh_info);
            if (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_OVERLAY)
            {
                p_overlay = (sys_nh_info_overlay_t*)p_nh_info;

            /* overlay bind with ecmp*/
            ecmp_group_id = p_overlay->ecmp_gid;
            use_dsnh_offset = (DRV_FROM_AT(lchip) && p_nhdb->h_ecmp_en && SYS_NH_OVERLAY_NEW_MODE(lchip));
                logic_dest_port = p_overlay->dest_logic_port;
                if (p_overlay->nhid && ((ecmp_group_id != 0) || use_dsnh_offset))
                {
                    nh_ptr_valid = 1;
                    nh_ptr = p_nh_info->hdr.dsnh_offset;
                    bypass_igs_edit = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
                    nh_ext = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
                }
            }
            else if (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_SRV6)
            {
                p_srv6 = (sys_nh_info_srv6_t*)p_nh_info;

                /* srv6 bind with ecmp*/
                ecmp_group_id = p_srv6->ecmp_if_id;
                if (ecmp_group_id != 0)
                {
                    nh_ptr_valid = 1;
                    nh_ptr = p_nh_info->hdr.dsnh_offset;
                    bypass_igs_edit = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
                    nh_ext = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
                }
            }
            else if(p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_ECMP)
            {
                sys_nh_info_ecmp_t *p_ecmp_nh = NULL;

                p_ecmp_nh = (sys_nh_info_ecmp_t*)p_nh_info;
                ecmp_group_id = p_ecmp_nh->ecmp_group_id;
            }
            tmp_gport = dsnh_info.gport;
            dsfwd_offset = DRV_FROM_AT(lchip)? p_nh_info->hdr.dsfwd1_offset : p_nh_info->hdr.dsfwd_offset;
        }
        else
        {
            sys_nh_db_srh_t* p_srh_tnl = NULL;
            sys_nh_db_arp_t* p_arp = NULL;
            ecmp_mem_id = ecmp_mem_idx % (p_nhdb->valid_cnt);
            p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nhdb->nh_array[ecmp_mem_id]);
            if (NULL == p_srh_tnl)
            {
                return CTC_E_NOT_EXIST;
            }
            p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_srh_tnl->arp_id));
            if (NULL == p_arp)
            {
                return CTC_E_NOT_EXIST;
            }
            CTC_ERROR_RETURN(sys_usw_nh_arp_alloc_dsfwd(lchip, p_arp, &dsfwd_offset));
            logic_dest_port = p_srh_tnl->ldp;
            tmp_gport = p_arp->gport;
        }

        if (ecmp_group_id == 0)
        {
            if (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY || p_nhdb->failover_en ||p_nhdb->ant_flow_en)
            {
                dmps_port_info.gport = tmp_gport;
                CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_CHAN_ID, &dest_channel));
            }
            else
            {
                dest_channel = 0xFFFF;
            }
            if (DRV_FROM_TMM(lchip) && p_nhdb->ant_flow_en)
            {
                field_val = p_nhdb->ecmp_group_id;
                cmd = DRV_IOW(DsChannelToEcmpGroupMap_t, DsChannelToEcmpGroupMap_ecmpGroupId_f);
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, dest_channel, cmd, &field_val));
            }
        }

        i = ecmp_mem_idx % 4;

        if (i == 0)
        {
            sal_memset(&sys_ecmp_member, 0, sizeof(sys_ecmp_member));
        }

        sys_ecmp_member.info[i].valid = 1;
        sys_ecmp_member.info[i].dsfwdptr = dsfwd_offset;
        sys_ecmp_member.info[i].dest_channel = dest_channel;

  
        sys_ecmp_member.info[i].logic_dest_port = logic_dest_port;

        /* overlay bind with vni or hecmp srv6*/
        if (nh_ptr_valid)
        {
            sys_ecmp_member.info[i].nexthop_ptr = nh_ptr;
            sys_ecmp_member.info[i].bypass_igs_edit = bypass_igs_edit;
            sys_ecmp_member.info[i].nexthop_ext = nh_ext;
        }

        sys_ecmp_member.info[i].ecmp_gid = ecmp_group_id;

        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update ECMP_MEMBER, i:%d, nhid:%d\n", i, p_nhdb->nh_array[ecmp_mem_id]);
        if (((ecmp_mem_idx + 1) == valid_cnt) || (ecmp_mem_idx % 4 == 3))
        {
            /* write ecmp member */
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Write ECMP_MEMBER, index:%d\n", (p_nhdb->ecmp_member_base + ecmp_mem_idx)/4);
            CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_MEMBER,
                                        (p_nhdb->ecmp_member_base + ecmp_mem_idx) / 4, &sys_ecmp_member));
        }
    }

    sys_ecmp_group.dlb_en = (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY) ? 1 : 0;
    sys_ecmp_group.failover_en = p_nhdb->failover_en ? 1 : 0;
    sys_ecmp_group.rr_en = ((p_nhdb->type == CTC_NH_ECMP_TYPE_RR) || (p_nhdb->type == CTC_NH_ECMP_TYPE_RANDOM_RR)) ? 1 : 0;
    sys_ecmp_group.member_base = p_nhdb->valid_cnt  ? (p_nhdb->ecmp_member_base >> 2) : (g_usw_nh_master[lchip]->ecmp_drop_mem_base[p_nhdb->h_ecmp_en] >> 2);
    sys_ecmp_group.member_num = p_nhdb->valid_cnt  ? (p_nhdb->valid_cnt-1) : 0;
    sys_ecmp_group.stats_valid = p_nhdb->valid_cnt ? p_nhdb->stats_valid : 0;
    sys_ecmp_group.ant_flow_en = p_nhdb->ant_flow_en;
    sys_ecmp_group.ant_flow_base = p_nhdb->ant_flow_base;

    if (sys_ecmp_group.rr_en)
    {
        sys_dsecmp_rr_t sys_ecmp_rr;

        if ( DRV_FROM_TMM(lchip)&& g_usw_nh_master[lchip]->h_ecmp_en)
        {
            sys_ecmp_group.rr_profile_id = p_nhdb->ecmp_group_id - ((MCHIP_CAP(SYS_CAP_NH_ECMP_GROUP_ID_NUM) + 1) / 2);
        }
        else
        {
            sys_ecmp_group.rr_profile_id = p_nhdb->ecmp_group_id - DRV_FROM_TMM(lchip);
        }
        sys_ecmp_rr.random_rr_en = p_nhdb->random_rr_en;
        sys_ecmp_rr.member_num = p_nhdb->valid_cnt-1;
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_RR_COUNT,
                sys_ecmp_group.rr_profile_id, &sys_ecmp_rr));
    }

    /* write ecmp group */
    CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_GROUP,
                p_nhdb->ecmp_group_id, &sys_ecmp_group));

    /*update hecmp group*/
    if (!is_create && DRV_IS_TSINGMA(lchip) && !(CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_update_hecmp_member(lchip, p_nhdb->hdr.nh_id, 0));
    }

	if (p_nhdb->rpf_en)
    {
        uint16 l3if_id;
        uint8 findflag = 0;
        int32 ret = 0;

        sal_memset(&rpf_info, 0, sizeof(rpf_info));
        for (ecmp_mem_idx = 0; ((ecmp_mem_idx < p_nhdb->valid_cnt)&&(rpf_info.rpf_intf_cnt < SYS_USW_MAX_RPF_IF_NUM)); ecmp_mem_idx++)
        {
            ret = sys_usw_nh_get_l3ifid(lchip, p_nhdb->nh_array[ecmp_mem_idx], &l3if_id);
            if(ret != CTC_E_NONE)
            {
                continue;
            }

            findflag = 0;
            for (i = 0; i < rpf_info.rpf_intf_cnt; i++)
            {
               if(l3if_id == rpf_info.rpf_intf[i])
               {
              	   findflag = 1;
              	   break;
               }
           }
            if(!findflag)
            {
                rpf_info.rpf_intf[rpf_info.rpf_intf_cnt] = l3if_id;
                rpf_info.rpf_intf_cnt++;
            }
        }

      if (!p_nhdb->valid_cnt)
      {
            /*Ecmp have no valid member, rpf check fail for strick mode*/
            rpf_info.rpf_intf[0] = 0xFFFF;
            rpf_info.rpf_intf_cnt++;
      }
      if (is_create)
      {
            rpf_info.nh_rpf  = 1 ;
            CTC_ERROR_RETURN(sys_usw_rpf_add_profile(lchip, &rpf_info));
            p_nhdb->rpf_id = rpf_info.rpf_id;
       }
       else
       {
           rpf_info.rpf_id = p_nhdb->rpf_id;
           rpf_info.nh_rpf  = 1 ;
           CTC_ERROR_RETURN(sys_usw_rpf_update_profile(lchip, &rpf_info));
       }
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_ecmp_interface_group(uint8 lchip, sys_l3if_ecmp_if_t* p_group)
{
    uint8 valid_nh_idx = 0;
    uint16 ecmp_mem_idx = 0;
    uint32 dest_channel = 0;
    uint16 max_ecmp = 0;
    uint32 dsfwd_offset = 0;
    uint32 cmd = 0;
    uint32 field_val = 0;
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_usw_dmps_port_info_t dmps_port_info = {0};
    sys_fwd_t dsfwd;
    sys_dsecmp_member_t sys_ecmp_member;
    sys_dsecmp_group_t sys_ecmp_group;
    sys_l3if_prop_t l3if_prop;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_PTR_VALID_CHECK(p_group);

    if (p_group->failover_en && (p_group->ecmp_group_type == CTC_NH_ECMP_TYPE_DLB || p_group->ecmp_group_type == CTC_NH_ECMP_TYPE_SPRAY))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
		return CTC_E_NOT_SUPPORT;
    }

    sal_memset(&sys_ecmp_member, 0, sizeof(sys_ecmp_member));
    sal_memset(&sys_ecmp_group, 0, sizeof(sys_ecmp_group));
    sal_memset(&dsfwd, 0, sizeof(dsfwd));
    sal_memset(&l3if_prop, 0, sizeof(l3if_prop));

    max_ecmp = SYS_USW_MAX_DEFAULT_ECMP_NUM;

    for (ecmp_mem_idx = 0; ecmp_mem_idx < max_ecmp; ecmp_mem_idx++)
    {
        if (p_group->intf_count == 0)
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, CTC_NH_RESERVED_NHID_FOR_DROP, (sys_nh_info_com_t**)&p_nh_info));
            dsfwd_offset = p_nh_info->hdr.dsfwd_offset;
        }
        else
        {
            l3if_prop.l3if_id = p_group->intf_array[valid_nh_idx];
            CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 1, &l3if_prop));
            dsfwd_offset = l3if_prop.cvlan_id; /*phy-if use sw cvlanid as dsfwd_offset*/
            if ((++valid_nh_idx) == p_group->intf_count)
            {
                valid_nh_idx = 0;
            }
        }
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " INFO: ecmp_mem_idx:%d()\n", ecmp_mem_idx);

        sys_usw_nh_get_entry_dsfwd(lchip, dsfwd_offset, (void*)&dsfwd, 0);
        dmps_port_info.gport = CTC_MAP_LPORT_TO_GPORT(SYS_DECODE_DESTMAP_GCHIP(dsfwd.dest_map), SYS_DECODE_DESTMAP_LPORT(dsfwd.dest_map));
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_CHAN_ID, &dest_channel));

        if (ecmp_mem_idx%4 == 0)
        {
            sal_memset(&sys_ecmp_member, 0, sizeof(sys_ecmp_member));
            sys_ecmp_member.info[0].valid = 1;
            sys_ecmp_member.info[0].dsfwdptr = dsfwd_offset;
            sys_ecmp_member.info[0].dest_channel = dest_channel;
        }
        else if (ecmp_mem_idx%4 == 1)
        {
            sys_ecmp_member.info[1].valid = 1;
            sys_ecmp_member.info[1].dsfwdptr = dsfwd_offset;
            sys_ecmp_member.info[1].dest_channel = dest_channel;
        }
        else if (ecmp_mem_idx%4 == 2)
        {
            sys_ecmp_member.info[2].valid = 1;
            sys_ecmp_member.info[2].dsfwdptr = dsfwd_offset;
            sys_ecmp_member.info[2].dest_channel = dest_channel;
        }
        else if (ecmp_mem_idx%4 == 3)
        {
            sys_ecmp_member.info[3].valid = 1;
            sys_ecmp_member.info[3].dsfwdptr = dsfwd_offset;
            sys_ecmp_member.info[3].dest_channel = dest_channel;

            /* write ecmp member */
            CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_MEMBER,
                (p_group->ecmp_member_base + ecmp_mem_idx)/4, &sys_ecmp_member));
        }

        if ((DRV_FROM_TMM(lchip)) && (SYS_DMPS_INVALID_CHAN_ID != dest_channel))
        {
            field_val = p_group->hw_group_id;
            cmd = DRV_IOW(DsChannelToEcmpGroupMap_t, DsChannelToEcmpGroupMap_ecmpGroupId_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, dest_channel, cmd, &field_val));
        }

    }

    sys_ecmp_group.dlb_en = (p_group->ecmp_group_type == CTC_NH_ECMP_TYPE_DLB || p_group->ecmp_group_type == CTC_NH_ECMP_TYPE_SPRAY) ? 1 : 0;
    sys_ecmp_group.failover_en = p_group->failover_en ? 1 : 0;
    sys_ecmp_group.member_base = p_group->ecmp_member_base / 4;
    sys_ecmp_group.member_num = (p_group->intf_count > 0) ? (p_group->intf_count-1) : 0;
    sys_usw_flow_stats_lookup_statsid(lchip, CTC_STATS_STATSID_TYPE_ECMP,p_group->hw_group_id, &field_val, 0);
    sys_ecmp_group.stats_valid = (field_val > 0) ? 1 : 0;

    CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_GROUP,
                p_group->hw_group_id, &sys_ecmp_group));

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_ol_ecmp_check(uint8 lchip, uint32 mem_nhid)
{
    sys_nh_info_com_t* p_nh_info = NULL;
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, mem_nhid, (sys_nh_info_com_t**)&p_nh_info));
    if (p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_ECMP && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_OVERLAY
        && (SYS_NH_TYPE_SRV6 != p_nh_info->hdr.nh_entry_type))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop type is invalid \n");
        return CTC_E_INVALID_CONFIG;
    }

    return CTC_E_NONE;
}

int32 
_sys_usw_nh_enable_spray_ecmp(uint8 lchip, uint8 ecmp_type, uint8 enable)
{
    sys_usw_nh_master_t *p_nh_master = g_usw_nh_master[lchip];
    uint32 field_value = 0;

    if (ecmp_type != CTC_NH_ECMP_TYPE_SPRAY && ecmp_type != CTC_NH_ECMP_TYPE_DLB)
    {
        return CTC_E_NONE;
    }
    if (ecmp_type == CTC_NH_ECMP_TYPE_SPRAY)
    {
        if (enable && p_nh_master->ecmp_spray_ref == 0 )
        {
            CTC_ERROR_RETURN(sys_usw_global_ctl_set(lchip, CTC_GLOBAL_ECMP_FLOW_INACTIVE_INTERVAL, &field_value));
            field_value = CTC_GLOBAL_ECMP_REBALANCE_MODE_NORMAL;
            CTC_ERROR_RETURN(sys_usw_global_ctl_set(lchip, CTC_GLOBAL_ECMP_REBALANCE_MODE, &field_value));
        }
        else if ((p_nh_master->ecmp_spray_ref == 1 && !enable))
        {
            field_value = 60000;/*default value, uint:us*/
            CTC_ERROR_RETURN(sys_usw_global_ctl_set(lchip, CTC_GLOBAL_ECMP_FLOW_INACTIVE_INTERVAL, &field_value));
        }
    }
    if (enable)
    {
        p_nh_master->ecmp_spray_ref = (ecmp_type == CTC_NH_ECMP_TYPE_SPRAY)? (p_nh_master->ecmp_spray_ref + 1) : (p_nh_master->ecmp_spray_ref - 1);
    }
    else
    {
        p_nh_master->ecmp_spray_ref = (ecmp_type == CTC_NH_ECMP_TYPE_SPRAY)? (p_nh_master->ecmp_spray_ref - 1) : (p_nh_master->ecmp_spray_ref + 1);
    }
    

    return CTC_E_NONE;
}

int32
sys_usw_nh_create_normal_ecmp(uint8 lchip, sys_nh_param_com_t* p_com_nh_param, sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_ecmp_t* p_nh_param = NULL;
    ctc_nh_ecmp_nh_param_t* p_nh_ecmp_param = NULL;
    sys_nh_info_ecmp_t* p_nhdb = NULL;
    sys_usw_opf_t opf;
    sys_stats_param_t sts_param;
    uint16 max_ecmp = 0;
    uint16  nh_array_size = 0;
    uint16  loop = 0, loop2 = 0;
    uint16 valid_cnt = 0, unrov_nh_cnt = 0;
    uint32* p_unrov_nh_array = NULL;
    uint32* p_valid_nh_array = NULL;
    uint32 offset = 0;
    sys_nh_db_srh_t* p_srh_tnl = NULL;
    int32  ret = CTC_E_NONE;

    sys_usw_nh_master_t *p_nh_master = g_usw_nh_master[lchip];


    sys_nh_info_com_t* p_nh_info = NULL;
    void** p_nh_info_array = NULL;
    void** p_unrov_nh_info_array = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&opf, 0, sizeof(opf));

    p_nh_param = (sys_nh_param_ecmp_t*)(p_com_nh_param);
    p_nhdb = (sys_nh_info_ecmp_t*)(p_com_db);
    p_nhdb->hdr.nh_entry_type = SYS_NH_TYPE_ECMP;
    p_nh_ecmp_param = p_nh_param->p_ecmp_param;

    CTC_MAX_VALUE_CHECK(p_nh_ecmp_param->nh_num, MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));

    if ((p_nh_ecmp_param->failover_en  +
        (p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_DLB) + (p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_SPRAY) +
        CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_SPM_EN)) > 1)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " ECMP not supported Failover and Dlb or session keep!\n");
        return CTC_E_NOT_SUPPORT;
    }

    if (CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP))
    {
        if (p_nh_master->h_ecmp_en == 0 || (p_nh_ecmp_param->type != CTC_NH_ECMP_TYPE_STATIC)
            || p_nh_ecmp_param->failover_en || CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_SPM_EN) || CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_RPF_PROFILE_EN))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Global configure not supported!\n");
            return CTC_E_NOT_SUPPORT;
        }
    }
    if (p_nh_master->ecmp_spray_ref)
    {
        uint8 is_dlb_used = (p_nh_master->ecmp_spray_ref < 0);
        if ((p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_DLB || p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_SPRAY) 
            && is_dlb_used == (p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_SPRAY))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Not support dlb and spray mode at the same time \n");
            return CTC_E_INVALID_CONFIG;
        }
    }

    if (CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP) && DRV_IS_TSINGMA(lchip))
    {
        return _sys_usw_nh_update_hecmp(lchip, p_nh_ecmp_param, p_nhdb, 1);
    }

    CTC_ERROR_RETURN(_sys_usw_nh_get_max_ecmp(lchip, &max_ecmp));

    p_unrov_nh_array = (uint32*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(uint32)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    p_valid_nh_array = (uint32*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(uint32)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    p_nh_info_array = (void**)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(void*)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    p_unrov_nh_info_array = (void**)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(void*)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    if ( (NULL == p_unrov_nh_array) || (NULL == p_valid_nh_array) || (NULL == p_nh_info_array) || (NULL == p_unrov_nh_info_array))
    {
        ret = CTC_E_NO_MEMORY;
        goto out;
    }

    sal_memset(p_unrov_nh_array, 0, sizeof(uint32)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    sal_memset(p_valid_nh_array, 0, sizeof(uint32)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    sal_memset(p_nh_info_array, 0, sizeof(void*)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));
    sal_memset(p_unrov_nh_info_array, 0, sizeof(void*)*MCHIP_CAP(SYS_CAP_NH_MAX_ECPN));

    /* group member num is flex */
    if (max_ecmp == 0)
    {
        if (p_nh_ecmp_param->member_num > MCHIP_CAP(SYS_CAP_NH_MAX_ECPN))
        {
            ret = CTC_E_INVALID_PARAM;
            goto out;
        }
        if (p_nh_ecmp_param->nh_num > p_nh_ecmp_param->member_num)
        {
            ret = CTC_E_NH_EXCEED_MAX_ECMP_NUM;
            goto out;
        }
        p_nhdb->mem_num = p_nh_ecmp_param->member_num;
    }
    else  /* group member num is fixed */
    {
        if (p_nh_ecmp_param->nh_num > max_ecmp)
        {
            ret = CTC_E_NH_EXCEED_MAX_ECMP_NUM;
            goto out;
        }
        p_nhdb->mem_num = max_ecmp;
    }

    /*2.Judge  Member is FWD or unrsv */
    valid_cnt = 0;
    unrov_nh_cnt = 0;
    p_nhdb->mem_is_tunnel = CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_MEM_IS_SRH) ? 1 : 0;

    if (p_nhdb->mem_is_tunnel)
    {
        for (loop = 0; loop < p_nh_ecmp_param->nh_num; loop++)
        {
            p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_ecmp_param->nhid[loop]);
            if (NULL == p_srh_tnl || (0 != p_srh_tnl->num && 0 == p_srh_tnl->ldp))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not exist or not config ldp!\n");
                ret = CTC_E_INVALID_PARAM;
                goto out;
            }
            if (0 == loop)
            {
                p_nhdb->tunnel_is_ldp = p_srh_tnl->num?1:0;
                p_nhdb->srh_replace_ipda = CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA)?0:1;
            }
            else if ((p_nhdb->tunnel_is_ldp != (p_srh_tnl->num?1:0)) || (p_nhdb->srh_replace_ipda != (CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA)?0:1)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not same!\n");
                ret = CTC_E_INVALID_PARAM;
                goto out;
            }
            p_nh_info_array[valid_cnt] = (void*)p_srh_tnl;
            p_valid_nh_array[valid_cnt++] = p_nh_ecmp_param->nhid[loop];
        }
    }
    else
    {
        for (loop = 0; loop < p_nh_ecmp_param->nh_num; loop++)
        {
            sys_nh_info_dsnh_t nh_info;
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));

        CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[loop], (sys_nh_info_com_t**)&p_nh_info), ret, out);
        if ( !CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP)  &&
            p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_IPUC
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_MPLS
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_IP_TUNNEL
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_MISC
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_DROP
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_TRILL
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_SRV6
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_OVERLAY
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_APS)

            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop type is invalid \n");
                ret = CTC_E_INVALID_CONFIG;
                goto out;
            }
            else if(CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP))
            {
                CTC_ERROR_GOTO(_sys_usw_nh_ol_ecmp_check(lchip, p_nh_ecmp_param->nhid[loop]), ret, out);
            }

        CTC_ERROR_GOTO(_sys_usw_nh_get_nhinfo(lchip, p_nh_ecmp_param->nhid[loop], &nh_info), ret, out);
        if ((SYS_MAP_CTC_GPORT_TO_GCHIP(nh_info.gport) == 0x1f ||  CTC_IS_CPU_PORT(nh_info.gport) ||
            (FALSE == sys_usw_chip_is_local(lchip, CTC_MAP_GPORT_TO_GCHIP(nh_info.gport)))) &&
            (p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_DLB || p_nh_ecmp_param->type == CTC_NH_ECMP_TYPE_SPRAY || p_nh_ecmp_param->failover_en || CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_SPM_EN)) &&
            (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop]Ecmp Dlb member cannot support linkagg \n");
            ret = CTC_E_INVALID_CONFIG;
            goto out;
        }

        if (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)
            && (p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_ECMP)
              &&!(p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_OVERLAY && (((sys_nh_info_overlay_t*)p_nh_info)->ecmp_gid)))
              {
                  uint32 dsfwd_offset = 0;
                  CTC_ERROR_GOTO(_sys_usw_nh_ecmp_get_dsfwd( lchip, p_nh_ecmp_param->nhid[loop], &dsfwd_offset), ret, out);
                  
                  if (DRV_FROM_AT(lchip) && (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_OVERLAY) && 
                    (!CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP) && SYS_NH_OVERLAY_NEW_MODE(lchip)))
                  {
                      sys_fwd_t sys_fwd= {0};
                      sys_fwd.offset = dsfwd_offset;
                      sys_fwd.is_dsfwd1 = 1;
                      sys_usw_nh_read_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD_HALF1, dsfwd_offset, &sys_fwd);
                      sys_fwd.nexthop_ptr = nh_info.dsnh_offset;
                      sys_fwd.bypass_igs_edit = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
                      sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD1, dsfwd_offset, &sys_fwd);
                  }
              }

        if (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
        {
                p_nh_info_array[valid_cnt] = (void*)p_nh_info;
                p_valid_nh_array[valid_cnt++] = p_nh_ecmp_param->nhid[loop];

            }
            else
            {
                p_unrov_nh_info_array[unrov_nh_cnt] = (void*)p_nh_info;
                p_unrov_nh_array[unrov_nh_cnt++] = p_nh_ecmp_param->nhid[loop];
            }

            if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN) &&
            ((p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_MPLS)||
            (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_SRV6)||
            (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_APS)))
            {
                CTC_ERROR_GOTO(sys_usw_nh_set_met_aps_en(lchip, p_nh_ecmp_param->nhid[loop], 1), ret, out);
            }

        }
    }

    if ((g_usw_nh_master[lchip]->cur_ecmp_cnt + 1) > g_usw_nh_master[lchip]->max_ecmp_group_num)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "ECMP Group have No resource in ASIC \n");
        ret = CTC_E_NO_RESOURCE;
        goto out;
    }

    /*3.Save DB */
    p_nhdb->valid_cnt = valid_cnt;
    p_nhdb->ecmp_cnt = valid_cnt + unrov_nh_cnt;
    p_nhdb->type = p_nh_ecmp_param->type;
    p_nhdb->failover_en = p_nh_ecmp_param->failover_en;
    p_nhdb->ant_flow_en = CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_SPM_EN);
    p_nhdb->h_ecmp_en = CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP)?1:0;
    p_nhdb->rpf_en = CTC_FLAG_ISSET(p_nh_ecmp_param->flag, CTC_NH_ECMP_FLAG_RPF_PROFILE_EN)?1:0;

    if(p_nhdb->ant_flow_en)
    {
        CTC_ERROR_GOTO(sys_usw_ftm_alloc_table_offset(lchip, DsAntFlowEcmp_t, 0, SYS_ECMP_SPM_ENTRY_NUM, 1, &offset), ret, out);
        p_nhdb->ant_flow_base = offset >> SYS_ECMP_SPM_TBL_BASE_WIDTH;
        _sys_usw_nh_ecmp_clear_ant_flow(lchip, p_nhdb, 0, 1);
    }
    if ((p_nhdb->type == CTC_NH_ECMP_TYPE_RR) || (p_nhdb->type == CTC_NH_ECMP_TYPE_RANDOM_RR))
    {
        uint32 rr_profile_id = 0;
        /* for rr, only support groupId 1-15 */

        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_group_opf_type;
        opf.pool_index = 0;
        opf.reverse    = 0;

        CTC_ERROR_GOTO(sys_usw_opf_alloc_offset(lchip, &opf, 1, &offset), ret, error00);
        rr_profile_id = offset;
        if (DRV_FROM_TMM(lchip))
        {
            rr_profile_id = offset - (p_nh_master->h_ecmp_en? ((MCHIP_CAP(SYS_CAP_NH_ECMP_GROUP_ID_NUM) + 1) / 2) : 1);
        }
        if (rr_profile_id >= MCHIP_CAP(SYS_CAP_NH_ECMP_RR_GROUP_NUM))
        {
            sys_usw_opf_free_offset(lchip, &opf, 1, offset);
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " ECMP RR Group num exceed max number,ecmp_group_id:%d \n", offset);
            ret = CTC_E_NO_RESOURCE;
            goto error00;
        }

        p_nhdb->ecmp_group_id = offset;

        if (p_nhdb->type == CTC_NH_ECMP_TYPE_RANDOM_RR)
        {
            p_nhdb->random_rr_en = 1;
        }

    }
    else
    {
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_group_opf_type;
        opf.pool_index = (p_nh_master->h_ecmp_en && p_nhdb->h_ecmp_en)?1:0;
        opf.reverse    = 1;
        CTC_ERROR_GOTO(sys_usw_opf_alloc_offset(lchip, &opf, 1, &offset), ret, error00);
        p_nhdb->ecmp_group_id = offset;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " INFO: alloc ecmp_group_id:%d\n", p_nhdb->ecmp_group_id);

    if(p_nhdb->mem_num)
     {
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
        opf.pool_index = p_nhdb->h_ecmp_en ?1:0;
        opf.multiple = SYS_ECMP_MEM_HW_SUB_NUM;
        opf.reverse    = 0;
        if(p_nhdb->mem_num > (MCHIP_CAP(SYS_CAP_NH_ECMP_MEMBER_NUM)-SYS_NH_ECMP_RESEVED_NUM - sys_usw_opf_get_alloced_cnt(lchip, &opf)))
        {
            ret = CTC_E_NO_RESOURCE;
            goto error0;
        }
         ret = sys_usw_opf_alloc_offset(lchip, &opf, p_nhdb->mem_num, &offset);
         if ((max_ecmp == 0) && (ret == CTC_E_NO_RESOURCE))   /* only flex mode support fragment process */
         {
             CTC_ERROR_GOTO(sys_usw_nh_ecmp_fragment(lchip, opf.pool_index), ret, error0);
             CTC_ERROR_GOTO(sys_usw_opf_alloc_offset(lchip, &opf, p_nhdb->mem_num, &offset), ret, error0);
         }
         else if(ret < 0)
         {
             goto error0;
         }
         p_nhdb->ecmp_member_base = offset;
    }

    /* process stats */
    if (p_nh_ecmp_param->stats_id)
    {
        sal_memset(&sts_param, 0, sizeof(sts_param));
        sts_param.id = p_nh_ecmp_param->stats_id;
        sts_param.ptr = p_nhdb->ecmp_group_id;
        sts_param.type = (p_nhdb->h_ecmp_en && DRV_FROM_AT(lchip)) ? SYS_STATS_TYPE_HECMP : SYS_STATS_TYPE_ECMP;
        ret = sys_usw_flow_stats_alloc_statsptr(lchip, &sts_param);
        if (ret < 0)
        {
            goto error1;
        }
        p_nhdb->stats_valid = 1;
    }

    if (0 != p_nhdb->ecmp_cnt)
    {
        nh_array_size = (p_nhdb->ecmp_cnt + SYS_ECMP_ALLOC_MEM_STEP - 1) / SYS_ECMP_ALLOC_MEM_STEP;
        nh_array_size = nh_array_size * SYS_ECMP_ALLOC_MEM_STEP;

        p_nhdb->nh_array = mem_malloc(MEM_NEXTHOP_MODULE, nh_array_size * sizeof(uint32));

        if (!p_nhdb->nh_array)
        {
            ret = CTC_E_NO_MEMORY;
            goto error2;
        }

        sal_memcpy(&p_nhdb->nh_array[0], &p_valid_nh_array[0], valid_cnt * sizeof(uint32));
        if (unrov_nh_cnt)
        {
            sal_memcpy(&p_nhdb->nh_array[valid_cnt], &p_unrov_nh_array[0], unrov_nh_cnt * sizeof(uint32));
            sal_memcpy(&p_nh_info_array[valid_cnt], &p_unrov_nh_info_array[0], unrov_nh_cnt * sizeof(void*));
        }
    }

    /*4.Create ECMP group */
    CTC_ERROR_GOTO(sys_usw_nh_update_ecmp_group(lchip, p_nhdb, 1), ret, error3);

    /*5.Add ECMP Nhid to member nexthop's linklist*/
    for (loop = 0; loop < p_nhdb->ecmp_cnt; loop++)
    {
        ret = sys_usw_nh_ecmp_add_ref_list(lchip, p_nhdb, p_nh_info_array[loop]);
        if (ret < 0)
        {
            for (loop2 = 0; loop2 < loop; loop2++)
            {
                /*rollback already add nhid member*/
                p_nhdb->nh_array[loop2] = 0;
                sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info_array[loop2]);
            }
            goto error3;
        }
    }

    ret = CTC_E_NONE;
    CTC_ERROR_GOTO(_sys_usw_nh_enable_spray_ecmp(lchip,p_nh_ecmp_param->type,1), ret, error3);
    goto out;

error3:
    if (p_nhdb->rpf_id)
    {
        sys_rpf_info_t rpf_info;
        sal_memset(&rpf_info, 0, sizeof(rpf_info));
        rpf_info.rpf_id = p_nhdb->rpf_id;
        rpf_info.nh_rpf = 1;
        sys_usw_rpf_remove_profile(lchip, &rpf_info);
    }
    mem_free(p_nhdb->nh_array);
error2:
    if (p_nh_ecmp_param->stats_id)
    {
        sys_usw_flow_stats_free_statsptr(lchip, &sts_param);
    }
error1:
    /* free ecmp groupId ? */
    {
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
        opf.pool_index = p_nhdb->h_ecmp_en?1:0;
        opf.reverse    = 0;
        sys_usw_opf_free_offset(lchip, &opf, p_nhdb->mem_num, (uint32)p_nhdb->ecmp_member_base);
    }
error0:
    opf.pool_type = g_usw_nh_master[lchip]->ecmp_group_opf_type;
    opf.pool_index =  (g_usw_nh_master[lchip]->h_ecmp_en && p_nhdb->h_ecmp_en)?1:0;
    sys_usw_opf_free_offset(lchip, &opf, 1, (uint32)(p_nhdb->ecmp_group_id));
error00:
    if(p_nhdb->ant_flow_en)
    {
        sys_usw_ftm_free_table_offset(lchip, DsAntFlowEcmp_t, 0, SYS_ECMP_SPM_ENTRY_NUM, (p_nhdb->ant_flow_base << SYS_ECMP_SPM_TBL_BASE_WIDTH));
    }
out:
    if (p_unrov_nh_array)
    {
        mem_free(p_unrov_nh_array);
    }
    if (p_valid_nh_array)
    {
        mem_free(p_valid_nh_array);
    }
    if (p_nh_info_array)
    {
        mem_free(p_nh_info_array);
    }
    if (p_unrov_nh_info_array)
    {
        mem_free(p_unrov_nh_info_array);
    }

    return ret;
}

int32
sys_usw_nh_replace_ecmp_member(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, ctc_nh_ecmp_nh_param_t* p_nh_ecmp_param)
{
    sys_usw_opf_t opf;
    uint16   max_ecmp = 0;
    int32     ret = 0;
    uint32   new_member_base = 0;
    sys_dsecmp_member_t sys_ecmp_member;
    sys_dsecmp_group_t sys_ecmp_group;
    uint16 mem_idx = 0,sub_idx;
    sys_nh_info_dsnh_t dsnh_info;
    sys_nh_info_com_t* p_nh_info = NULL;
    uint32 dsfwd_offset =  0;
    uint8 findflag = 0;
    uint32  *nh_array = NULL;
    uint16 valid_cnt = 0;
    uint32 field_val = 0;
    uint32 cmd = 0;
    uint32 chan_id = 0;
    sys_usw_dmps_port_info_t dmps_port_info = {0};
    sys_rpf_info_t rpf_info;
    uint32 tmp_gport = 0;
    uint32 logic_dest_port = 0;
    uint8 nh_ptr_valid = 0;
    uint32 nh_ptr = 0;
    uint8 bypass_igs_edit = 0;
    uint8 nh_ext = 0;
    sys_nh_db_srh_t* p_srh_tnl = NULL;
    void** p_nh_info_array = NULL;
    void* p_tmp_nh_info = NULL;

    CTC_ERROR_RETURN(_sys_usw_nh_get_max_ecmp(lchip, &max_ecmp));

    if(max_ecmp !=0 )
    {
       return CTC_E_INVALID_PARAM;
    }
    if((p_nhdb->h_ecmp_en && !DRV_FROM_TMM(lchip)) || ((p_nhdb->type == CTC_NH_ECMP_TYPE_RR) || (p_nhdb->type == CTC_NH_ECMP_TYPE_RANDOM_RR)) ||
        (p_nh_ecmp_param->nh_num  > CTC_MAX_ECPN) ||  !(((p_nh_ecmp_param->nh_num  ==  CTC_CONST256
        || p_nh_ecmp_param->nh_num  ==  CTC_CONST512
        || p_nh_ecmp_param->nh_num  ==  CTC_CONST1024
        || p_nh_ecmp_param->nh_num  ==  CTC_CONST2048
        || p_nh_ecmp_param->nh_num  ==  CTC_CONST4096
        || p_nh_ecmp_param->nh_num  ==  CTC_CONST128
        || p_nh_ecmp_param->nh_num < CTC_CONST128) && DRV_FROM_TMM(lchip))
        || (! DRV_FROM_TMM(lchip)  &&  (p_nh_ecmp_param->nh_num <= CTC_CONST64))))
     {
          return CTC_E_INVALID_PARAM;
     }

     if(p_nh_ecmp_param->nh_num)
     {
        nh_array = mem_malloc(MEM_NEXTHOP_MODULE, p_nh_ecmp_param->nh_num* sizeof(uint32));
        p_nh_info_array = (void**)mem_malloc(MEM_NEXTHOP_MODULE, p_nh_ecmp_param->nh_num* sizeof(void*));
        if(!nh_array || (NULL == p_nh_info_array))
        {
            ret = CTC_E_NO_MEMORY;
             goto error0;
       }
    }

    if (p_nhdb->mem_is_tunnel)
    {
        for (mem_idx = 0; mem_idx < p_nh_ecmp_param->nh_num && valid_cnt < p_nh_ecmp_param->nh_num ;)
        {
            p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_ecmp_param->nhid[mem_idx]);
            if (NULL == p_srh_tnl || (0 != p_srh_tnl->num && 0 == p_srh_tnl->ldp))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not exist or without ldp!\n");
                ret = CTC_E_INVALID_PARAM;
                goto error0;
            }
            if (0 == mem_idx)
            {
                p_nhdb->tunnel_is_ldp = p_srh_tnl->num?1:0;
                p_nhdb->srh_replace_ipda = CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA)?0:1;
            }
            else if ((p_nhdb->tunnel_is_ldp != (p_srh_tnl->num?1:0)) || (p_nhdb->srh_replace_ipda != (CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA)?0:1)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH type not same!\n");
                ret = CTC_E_INVALID_PARAM;
                goto error0;
            }
            p_nh_info_array[valid_cnt] = (void*)p_srh_tnl;
            nh_array[valid_cnt++] = p_nh_ecmp_param->nhid[mem_idx];
            if((mem_idx +1) == p_nh_ecmp_param->nh_num && valid_cnt && valid_cnt < p_nh_ecmp_param->nh_num
                && (p_nh_ecmp_param->nh_num >  MCHIP_CAP(SYS_CAP_NH_MAX_ECPN)))
            { 
                mem_idx = 0; 
                continue;
            }  
            mem_idx++; 
        }
    }
    else
    {
    for (mem_idx = 0; mem_idx < p_nh_ecmp_param->nh_num && valid_cnt < p_nh_ecmp_param->nh_num ;)
    {
       CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[mem_idx], (sys_nh_info_com_t**)&p_nh_info), ret, error0);


        if (!p_nhdb->h_ecmp_en && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_IPUC
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_MPLS
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_IP_TUNNEL
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_MISC
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_TRILL
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_SRV6
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_OVERLAY
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_APS)
        {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop type is invalid \n");
                ret =  CTC_E_INVALID_CONFIG;
               goto error0;
        }
       else if (p_nhdb->h_ecmp_en)
       {
           CTC_ERROR_GOTO(_sys_usw_nh_ol_ecmp_check(lchip, p_nh_ecmp_param->nhid[mem_idx]), ret, error0);
       }

            if(!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
            {
                p_nh_info_array[valid_cnt] = (void*)p_nh_info;
                nh_array[valid_cnt++] = p_nh_ecmp_param->nhid[mem_idx];
            }
            if((mem_idx +1) == p_nh_ecmp_param->nh_num && valid_cnt && valid_cnt < p_nh_ecmp_param->nh_num
                && (p_nh_ecmp_param->nh_num >  MCHIP_CAP(SYS_CAP_NH_MAX_ECPN)))
            {
                mem_idx = 0;
                continue;
            }
            mem_idx++;
        }
    }
    opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
    opf.pool_index = p_nhdb->h_ecmp_en ?1:0;
    opf.multiple    = SYS_ECMP_MEM_HW_SUB_NUM;
    opf.reverse     = 0;

    if(valid_cnt !=0)
    {
         ret = sys_usw_opf_alloc_offset(lchip, &opf,valid_cnt, &new_member_base);
         if (ret == CTC_E_NO_RESOURCE)
         {
             CTC_ERROR_GOTO(sys_usw_nh_ecmp_fragment(lchip, opf.pool_index),ret,error0);
             CTC_ERROR_GOTO(sys_usw_opf_alloc_offset(lchip, &opf, valid_cnt, &new_member_base),ret,error0);
         }
         else if (ret < 0)
         {
            CTC_ERROR_GOTO(ret,ret,error0);
         }
    }

    for (mem_idx = 0; mem_idx < valid_cnt; mem_idx++)
    {
         sys_nh_info_overlay_t* p_overlay = NULL;
         sys_nh_info_srv6_t* p_srv6 = NULL;
         uint32 ecmp_group_id = 0;

        logic_dest_port = 0;
        ecmp_group_id = 0;
        dsfwd_offset = 0;
        tmp_gport = 0;
        p_nh_info = NULL;
        if (0 == p_nhdb->mem_is_tunnel)
        {
            sal_memset(&dsnh_info, 0, sizeof(dsnh_info));
            _sys_usw_nh_get_nhinfo(lchip, nh_array[mem_idx], &dsnh_info);
            CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nh_array[mem_idx], (sys_nh_info_com_t**)&p_nh_info), ret, error0);

            if (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_OVERLAY)
            {
                uint8 use_dsnh_offset = 0;
                p_overlay = (sys_nh_info_overlay_t*)p_nh_info;
                /* overlay bind with ecmp*/
                ecmp_group_id = p_overlay->ecmp_gid;
                logic_dest_port = p_overlay->dest_logic_port;
                use_dsnh_offset = (DRV_FROM_AT(lchip) && p_nhdb->h_ecmp_en && SYS_NH_OVERLAY_NEW_MODE(lchip));
                if (p_overlay->nhid && (ecmp_group_id != 0 || use_dsnh_offset))
                {
                    nh_ptr_valid = 1;
                    nh_ptr = p_nh_info->hdr.dsnh_offset;
                    bypass_igs_edit = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
                    nh_ext = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
                }
            }
            else if (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_SRV6)
            {
                p_srv6 = (sys_nh_info_srv6_t*)p_nh_info;

                /* srv6 bind with ecmp*/
                ecmp_group_id = p_srv6->ecmp_if_id;
                if (ecmp_group_id != 0)
                {
                    nh_ptr_valid = 1;
                    nh_ptr = p_nh_info->hdr.dsnh_offset;
                    bypass_igs_edit = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
                    nh_ext = CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
                }
            }
            else if(p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_ECMP)
            {
                sys_nh_info_ecmp_t *p_ecmp_nh = NULL;
                p_ecmp_nh = (sys_nh_info_ecmp_t*)p_nh_info;
                ecmp_group_id = p_ecmp_nh->ecmp_group_id;
            }

            if ((SYS_MAP_CTC_GPORT_TO_GCHIP(dsnh_info.gport) == 0x1f ||  CTC_IS_CPU_PORT(dsnh_info.gport) ||
                (FALSE == sys_usw_chip_is_local(lchip, CTC_MAP_GPORT_TO_GCHIP(dsnh_info.gport)))) &&
                (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY || p_nhdb->failover_en || p_nhdb->ant_flow_en) &&
                (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop]Ecmp Dlb member cannot support linkagg \n");
                ret =   CTC_E_INVALID_CONFIG;
                goto error1;
            }

            if(!ecmp_group_id)
            {
                CTC_ERROR_GOTO(_sys_usw_nh_ecmp_get_dsfwd( lchip, nh_array[mem_idx], &dsfwd_offset), ret, error1);
            }
            tmp_gport = dsnh_info.gport;
        }
        else
        {
            sys_nh_db_arp_t* p_arp = NULL;
            p_srh_tnl = (sys_nh_db_srh_t*)p_nh_info_array[mem_idx];
            p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_srh_tnl->arp_id));
            if (NULL == p_arp)
            {
                goto error1;
            }
            CTC_ERROR_GOTO(sys_usw_nh_arp_alloc_dsfwd(lchip, p_arp,  &dsfwd_offset), ret, error1);
            logic_dest_port = p_srh_tnl->ldp;
            tmp_gport = p_arp->gport;
        }

        dmps_port_info.gport = tmp_gport;
        if (DRV_FROM_TMM(lchip) && p_nhdb->ant_flow_en && !ecmp_group_id)
        {
            field_val = p_nhdb->ecmp_group_id;
            CTC_ERROR_GOTO(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_CHAN_ID, &chan_id), ret, error1);
            cmd = DRV_IOW(DsChannelToEcmpGroupMap_t, DsChannelToEcmpGroupMap_ecmpGroupId_f);
            DRV_FIELD_IOCTL(lchip, chan_id, cmd, &field_val);

         }
         sub_idx= mem_idx % 4;
         if (sub_idx == 0)
         {
              sal_memset(&sys_ecmp_member, 0, sizeof(sys_ecmp_member));
         }
         CTC_ERROR_GOTO(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_CHAN_ID, &chan_id), ret, error1);
        sys_ecmp_member.info[sub_idx].valid = 1;
        sys_ecmp_member.info[sub_idx].dsfwdptr = dsfwd_offset;
        sys_ecmp_member.info[sub_idx].dest_channel = (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY || p_nhdb->failover_en || p_nhdb->ant_flow_en)? chan_id : 0xffff;

        sys_ecmp_member.info[sub_idx].logic_dest_port = logic_dest_port;
        /* overlay bind with vni*/
        if (nh_ptr_valid)
        {
            sys_ecmp_member.info[sub_idx].nexthop_ptr = nh_ptr;
            sys_ecmp_member.info[sub_idx].bypass_igs_edit = bypass_igs_edit;
            sys_ecmp_member.info[sub_idx].nexthop_ext = nh_ext;
        }

        sys_ecmp_member.info[sub_idx].ecmp_gid = ecmp_group_id;
        if (((mem_idx + 1) == valid_cnt) || (mem_idx % 4 == 3))
        {
            /* write ecmp member */
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Write ECMP_MEMBER, index:%d\n", (new_member_base + mem_idx)/4);
           CTC_ERROR_GOTO(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_MEMBER,
                                        (new_member_base + mem_idx) / 4, &sys_ecmp_member), ret, error1);

        }
        CTC_ERROR_GOTO(sys_usw_nh_ecmp_add_ref_list(lchip, p_nhdb, p_nh_info_array[mem_idx]), ret, error1);

        if (p_nh_info && CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN) &&
          ((p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_MPLS)||
          (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_SRV6)||
          (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_APS)))
        {
            CTC_ERROR_GOTO(sys_usw_nh_set_met_aps_en(lchip, nh_array[mem_idx], 1), ret, error1);
        }
    }

    if(p_nh_ecmp_param->nh_num || p_nhdb->mem_num)
    {
        sal_memset(&sys_ecmp_group,0,sizeof(sys_ecmp_group));
        sys_ecmp_group.member_base = valid_cnt ? (new_member_base >> 2) : (g_usw_nh_master[lchip]->ecmp_drop_mem_base[p_nhdb->h_ecmp_en] >> 2);
        sys_ecmp_group.member_num = valid_cnt ? (valid_cnt-1) : 0;
        sys_ecmp_group.stats_valid = valid_cnt ? p_nhdb->stats_valid : 0;
        sys_ecmp_group.ant_flow_en = p_nhdb->ant_flow_en;
        sys_ecmp_group.ant_flow_base = p_nhdb->ant_flow_base;
        sys_ecmp_group.dlb_en = 0;
        sys_ecmp_group.failover_en = p_nhdb->failover_en ? 1 : 0;

        if (valid_cnt > CTC_CONST128)
        {
            sys_ecmp_group.member_num = 0x80;
            if(valid_cnt>=CTC_CONST2048)
            {
                sys_ecmp_group.member_num |= (valid_cnt == CTC_CONST2048)?0x4:0x5;
            }
            else
            {
                sys_ecmp_group.member_num |= (valid_cnt == CTC_CONST256)?0x1:((valid_cnt == CTC_CONST512)?0x2:0x3);
            }
        }
        /* write ecmp group */
        CTC_ERROR_GOTO( sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_GROUP, p_nhdb->ecmp_group_id, &sys_ecmp_group), ret, error1);
     }

    /* the old member is removed from new ecmp group */
    max_ecmp = p_nhdb->ecmp_cnt ;
    p_nhdb->ecmp_cnt = 0;   /*for delete all same ecmp member */
     for (mem_idx = 0; mem_idx < max_ecmp ; mem_idx++)
    {
        findflag = 0;
        for (sub_idx = 0; sub_idx < valid_cnt; sub_idx++)
        {
            if (p_nhdb->nh_array[mem_idx] == nh_array[sub_idx] )
            {
                findflag = 1;
                break;
            }
        }
        if(!findflag)
        {
            if (p_nhdb->mem_is_tunnel)
            {
                p_tmp_nh_info = (void*)_sys_usw_nh_lkup_srh_id(lchip, p_nhdb->nh_array[mem_idx]);
            }
            else
            {
                sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nhdb->nh_array[mem_idx], (sys_nh_info_com_t**)&p_tmp_nh_info);
            }
            if (p_tmp_nh_info)
            {
                sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_tmp_nh_info);
            }
        }
    }

   if(p_nhdb->mem_num)
   {
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
        opf.pool_index = p_nhdb->h_ecmp_en ?1:0;
        opf.reverse     = 0;
        sys_usw_opf_free_offset(lchip, &opf, p_nhdb->mem_num, (uint32)p_nhdb->ecmp_member_base);
        mem_free( p_nhdb->nh_array);
   }

    if (p_nhdb->rpf_en)
    {
        uint16 l3if_id;
        sal_memset(&rpf_info, 0, sizeof(rpf_info));
        for (mem_idx = 0; ((mem_idx < valid_cnt)&&(rpf_info.rpf_intf_cnt < SYS_USW_MAX_RPF_IF_NUM)); mem_idx++)
        {
            ret = sys_usw_nh_get_l3ifid(lchip, nh_array[mem_idx], &l3if_id);
			if(ret != CTC_E_NONE)
			{
				continue;
			}
			findflag = 0;
   		    for (sub_idx = 0; sub_idx < rpf_info.rpf_intf_cnt; sub_idx++)
            {
               if(l3if_id == rpf_info.rpf_intf[sub_idx])
               {
              	   findflag = 1;
              	   break;
               }
           }
		   if(!findflag)
		   {
		      rpf_info.rpf_intf[rpf_info.rpf_intf_cnt] = l3if_id;
		      rpf_info.rpf_intf_cnt++;
		   }
        }
        if (!valid_cnt)
        {
            /*Ecmp have no valid member, rpf check fail for strick mode*/
            rpf_info.rpf_intf[0] = 0xFFFF;
            rpf_info.rpf_intf_cnt++;
        }
		rpf_info.nh_rpf = 1;
        rpf_info.rpf_id = p_nhdb->rpf_id;
		ret = sys_usw_rpf_update_profile(lchip, &rpf_info);
    }

   if(!valid_cnt)   mem_free(nh_array);
    p_nhdb->nh_array  = nh_array;
    p_nhdb->valid_cnt  = valid_cnt;
    p_nhdb->ecmp_cnt  = valid_cnt;
    p_nhdb->mem_num = valid_cnt;
    p_nhdb->ecmp_member_base = new_member_base;
    /*clear dlb flow table*/
    if(p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY)
    {
        uint8 loop = 0;
        uint8 loop_end = DRV_FROM_AT(lchip) ? SYS_PP_NUM(lchip) : 1;
        for(loop = 0; loop < loop_end; loop++)
        {
            MCHIP_NH(lchip)->clear_dlb_flow(lchip + loop, p_nhdb);
        }
        if (p_nh_ecmp_param->nh_num || p_nhdb->mem_num)
        {
            sys_ecmp_group.dlb_en = 1;
            /* write ecmp group */
            sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_ECMP_GROUP, p_nhdb->ecmp_group_id, &sys_ecmp_group);
        }
    }

    if (p_nh_info_array)
    {
        mem_free(p_nh_info_array);
    }

    return ret;
error1:
    /* the new member is removed from new ecmp group */
    for (mem_idx = 0; mem_idx <  valid_cnt ; mem_idx++)
    {
        findflag = 0;
        for (sub_idx = 0; sub_idx < p_nhdb->valid_cnt; sub_idx++)
        {
            if (nh_array[mem_idx] == p_nhdb->nh_array[sub_idx] )
            {
                findflag = 1;
                break;
            }
        }
        if(!findflag)
        {
            sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info_array[mem_idx]);
        }
    }
     if(valid_cnt)  sys_usw_opf_free_offset(lchip, &opf, valid_cnt, (uint32) new_member_base);
 error0:
     mem_free(nh_array);
     mem_free(p_nh_info_array);
    return ret;
}

int32
_sys_usw_nh_update_ecmp_cb(uint8 lchip, sys_nh_info_ecmp_t* p_nhdb, ctc_nh_ecmp_nh_param_t* p_nh_ecmp_param)
{
    uint32* old_nh_array;
    uint16 nh_array_size = 0, nh_array_size2 = 0;
    uint16 loop = 0, loop2 = 0;
    uint16 valid_cnt = 0;
    uint8 exist = 0;
    uint16  unrov_nh_cnt = 0;
    uint32 unrov_nh_array[SYS_USW_MAX_ECPN] = {0};
    uint32 valid_nh_array[SYS_USW_MAX_ECPN] = {0};
    void**  p_nh_info_array = NULL;
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_db_srh_t* p_srh_tnl = NULL;
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_nh_info_array = (void**)mem_malloc(MEM_NEXTHOP_MODULE, SYS_USW_MAX_ECPN* sizeof(void*));
    if(NULL == p_nh_info_array)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_nh_info_array, 0, sizeof(void*)*SYS_USW_MAX_ECPN);
    sal_memcpy(&valid_nh_array[0], &p_nhdb->nh_array[0], p_nhdb->valid_cnt * sizeof(uint32));
    sal_memcpy(&unrov_nh_array[0], &p_nhdb->nh_array[p_nhdb->valid_cnt], (p_nhdb->ecmp_cnt - p_nhdb->valid_cnt) * sizeof(uint32));
    unrov_nh_cnt = (p_nhdb->ecmp_cnt - p_nhdb->valid_cnt);
    valid_cnt = p_nhdb->valid_cnt;

    /*only support update one member*/
    if (p_nh_ecmp_param->upd_type == CTC_NH_ECMP_ADD_MEMBER)
    {
        sys_nh_info_dsnh_t nh_info;
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));

        if ((p_nhdb->ecmp_cnt + p_nh_ecmp_param->nh_num) > p_nhdb->mem_num)
        {
            ret = CTC_E_INVALID_PARAM;
            goto error0;
        }

        for (loop2 = 0; loop2 < p_nhdb->ecmp_cnt; loop2++)
        {
            if (p_nh_ecmp_param->nhid[0] == p_nhdb->nh_array[loop2]
                && ((p_nhdb->type != CTC_NH_ECMP_TYPE_STATIC) || p_nhdb->h_ecmp_en))
            {
                /*only staic ecmp support repeated Member*/
                ret = CTC_E_INVALID_CONFIG;
                goto error0;
            }
        }

        if (p_nhdb->h_ecmp_en && (SYS_GET_CHIP_VERSION != SYS_CHIP_SUB_VERSION_A) && DRV_IS_TSINGMA(lchip))
        {
            CTC_ERROR_RETURN(_sys_usw_nh_update_hecmp(lchip, p_nh_ecmp_param, p_nhdb, 0));
            ret = CTC_E_NONE;
            goto error0;
        }

        if (p_nhdb->mem_is_tunnel)
        {
            p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_ecmp_param->nhid[loop]);
            if (NULL == p_srh_tnl || (0 != p_srh_tnl->num && 0 == p_srh_tnl->ldp))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not exist or without ldp!\n");
                ret = CTC_E_INVALID_PARAM;
                goto error0;
            }

            if (0 == valid_cnt)
            {
                p_nhdb->tunnel_is_ldp = p_srh_tnl->num?1:0;
                p_nhdb->srh_replace_ipda = CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA)?0:1;
            }
            else if ((p_nhdb->tunnel_is_ldp != (p_srh_tnl->num?1:0)) || (p_nhdb->srh_replace_ipda != (CTC_FLAG_ISSET(p_srh_tnl->flag, SYS_NH_SRH_FLAG_DENY_REPLACE_IPDA)?0:1)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] SRH not same!\n");
                ret = CTC_E_INVALID_PARAM;
                goto error0;
            }
            
            p_nh_info_array[loop] = (void*)p_srh_tnl;
            valid_nh_array[valid_cnt++] = p_nh_ecmp_param->nhid[loop];
            p_nhdb->valid_cnt = valid_cnt;
        }
        else
        {
            CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[loop], (sys_nh_info_com_t**)&p_nh_info), ret, error0);
            if (!p_nhdb->h_ecmp_en &&
                p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_IPUC
                && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_MPLS
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_IP_TUNNEL
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_MISC
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_DROP
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_TRILL
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_SRV6
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_OVERLAY
            && p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_APS)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop type is invalid \n");
                ret = CTC_E_INVALID_CONFIG;
                goto error0;
            }
            else if (p_nhdb->h_ecmp_en)
            {
                CTC_ERROR_GOTO(_sys_usw_nh_ol_ecmp_check(lchip, p_nh_ecmp_param->nhid[loop]), ret, error0);
            }

            CTC_ERROR_GOTO(_sys_usw_nh_get_nhinfo(lchip, p_nh_ecmp_param->nhid[loop], &nh_info), ret, error0);
            if ((SYS_MAP_CTC_GPORT_TO_GCHIP(nh_info.gport) == 0x1f ||  CTC_IS_CPU_PORT(nh_info.gport) ||
                (FALSE == sys_usw_chip_is_local(lchip, CTC_MAP_GPORT_TO_GCHIP(nh_info.gport)))) &&
                (p_nhdb->type == CTC_NH_ECMP_TYPE_DLB || p_nhdb->type == CTC_NH_ECMP_TYPE_SPRAY || p_nhdb->failover_en || p_nhdb->ant_flow_en) &&
                (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop]Ecmp Dlb member cannot support linkagg \n");
                ret = CTC_E_INVALID_CONFIG;
                goto error0;
            }

            if (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)
                && (p_nh_info->hdr.nh_entry_type != SYS_NH_TYPE_ECMP) &&
                !(p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_OVERLAY && ((((sys_nh_info_overlay_t*)p_nh_info)->ecmp_gid))))
            {
                uint32 dsfwd_offset = 0;
                CTC_ERROR_GOTO(_sys_usw_nh_ecmp_get_dsfwd( lchip, p_nh_ecmp_param->nhid[loop], &dsfwd_offset), ret, error0);
            }

            p_nh_info_array[loop] = (void*)p_nh_info;
            if (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
            {
                valid_nh_array[valid_cnt++] = p_nh_ecmp_param->nhid[loop];
            }
            else
            {
                unrov_nh_array[unrov_nh_cnt++] = p_nh_ecmp_param->nhid[loop];
            }
            if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN) &&
            ((p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_MPLS)||
            (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_SRV6)||
            (p_nh_info->hdr.nh_entry_type == SYS_NH_TYPE_APS)))
            {
                CTC_ERROR_GOTO(sys_usw_nh_set_met_aps_en(lchip, p_nh_ecmp_param->nhid[loop], 1), ret, error0);
            }
        }
    }
    else if (p_nh_ecmp_param->upd_type == CTC_NH_ECMP_REMOVE_MEMBER)
    {
        for (loop2 = 0; loop2 < p_nhdb->ecmp_cnt; loop2++)
        {
            if (p_nh_ecmp_param->nhid[0] == p_nhdb->nh_array[loop2])
            {
                exist = 1;
                break;
            }
        }
        if (exist == 0)
        {
           SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] ECMP member not exist! \n");
           ret = CTC_E_NOT_EXIST;
           goto error0;
        }

        if (p_nhdb->h_ecmp_en && (SYS_GET_CHIP_VERSION != SYS_CHIP_SUB_VERSION_A) && DRV_IS_TSINGMA(lchip))
        {
            CTC_ERROR_GOTO(_sys_usw_nh_update_hecmp(lchip, p_nh_ecmp_param, p_nhdb, 0), ret, error0);
            ret = CTC_E_NONE;
            goto error0;
        }

        if (p_nhdb->mem_is_tunnel)
        {
            p_srh_tnl = _sys_usw_nh_lkup_srh_id(lchip, p_nh_ecmp_param->nhid[loop]);
            if (NULL == p_srh_tnl)
            {
                ret = CTC_E_NOT_EXIST;
                goto error0;
            }
            p_nh_info_array[loop] = (void*)p_srh_tnl;
        }
        else
        {
            CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_ecmp_param->nhid[loop], (sys_nh_info_com_t**)&p_nh_info), ret, error0);
            p_nh_info_array[loop] = (void*)p_nh_info;
        }

        /*loop2 is the position of remove member*/
        if (loop2 < valid_cnt)
        {
            valid_nh_array[loop2] = valid_nh_array[valid_cnt - 1];
            valid_cnt--;
        }
        else
        {
            unrov_nh_array[loop2 - valid_cnt] = unrov_nh_array[unrov_nh_cnt - 1];
            unrov_nh_cnt--;
        }
        _sys_usw_nh_ecmp_clear_ant_flow(lchip, p_nhdb, p_nh_ecmp_param->nhid[0], 0);
    }
    else
    {
        ret = CTC_E_INVALID_PARAM;
        goto error0;
    }

    /*old nh_array_size*/
    nh_array_size = (p_nhdb->ecmp_cnt + SYS_ECMP_ALLOC_MEM_STEP - 1) / SYS_ECMP_ALLOC_MEM_STEP;

    /*new nh_array_size*/
    nh_array_size2 = (valid_cnt + unrov_nh_cnt + SYS_ECMP_ALLOC_MEM_STEP - 1) / SYS_ECMP_ALLOC_MEM_STEP;
    nh_array_size2  = (nh_array_size2 == 0) ? 1 : nh_array_size2;

    if (nh_array_size != nh_array_size2)
    {
        old_nh_array = p_nhdb->nh_array;
        nh_array_size2 = nh_array_size2 * SYS_ECMP_ALLOC_MEM_STEP;
        p_nhdb->nh_array = mem_malloc(MEM_NEXTHOP_MODULE, nh_array_size2 * sizeof(uint32));
        if (!p_nhdb->nh_array)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            p_nhdb->nh_array = old_nh_array;
            ret = CTC_E_NO_MEMORY;
            goto error0;
        }

        mem_free(old_nh_array);
    }

    p_nhdb->valid_cnt = valid_cnt;
    p_nhdb->ecmp_cnt = valid_cnt + unrov_nh_cnt;
    sal_memcpy(&p_nhdb->nh_array[0], &valid_nh_array[0], valid_cnt * sizeof(uint32));
    if (unrov_nh_cnt)
    {
        sal_memcpy(&p_nhdb->nh_array[valid_cnt], &unrov_nh_array[0], unrov_nh_cnt * sizeof(uint32));
    }

    if (p_nhdb->type != CTC_NH_ECMP_TYPE_XERSPAN)
    {
        CTC_ERROR_GOTO(sys_usw_nh_update_ecmp_group(lchip, p_nhdb, 0), ret, error0);
    }
    else
    {
        CTC_ERROR_GOTO(sys_usw_nh_update_xerspan_group(lchip, p_nhdb), ret, error0);
    }

    if (p_nh_ecmp_param->upd_type == CTC_NH_ECMP_ADD_MEMBER)
    {
        if (CTC_MAX_UINT32_VALUE != p_nh_ecmp_param->nhid[0])
        {
            CTC_ERROR_GOTO(sys_usw_nh_ecmp_add_ref_list(lchip, p_nhdb, p_nh_info_array[loop]), ret, error0);
        }
    }
    else if (p_nh_ecmp_param->upd_type == CTC_NH_ECMP_REMOVE_MEMBER)
    {
        if (CTC_MAX_UINT32_VALUE != p_nh_ecmp_param->nhid[0])
        {
            CTC_ERROR_GOTO(sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info_array[loop]), ret, error0);
        }
    }

error0:
    mem_free(p_nh_info_array);

    return ret;
}
int32
sys_usw_nh_update_ecmp_cb(uint8 lchip, sys_nh_info_com_t* p_com_db, sys_nh_param_com_t* p_com_nh_param)
{

    sys_nh_param_ecmp_t* p_nh_param = NULL;
    ctc_nh_ecmp_nh_param_t* p_nh_ecmp_param = NULL;
    ctc_nh_ecmp_nh_param_t ecmp_param;
    sys_nh_info_ecmp_t* p_nhdb = NULL;
    uint16 loop = 0;
	int32  ret = 0;

    p_nh_param = (sys_nh_param_ecmp_t*)(p_com_nh_param);
    p_nh_ecmp_param = p_nh_param->p_ecmp_param;
    p_nhdb = (sys_nh_info_ecmp_t*)(p_com_db);

    CTC_EQUAL_CHECK(SYS_NH_TYPE_ECMP, p_com_db->hdr.nh_entry_type);

    if(p_nh_ecmp_param->upd_type == CTC_NH_ECMP_REPLACE_MEMBER)
    {
         return  sys_usw_nh_replace_ecmp_member(lchip,p_nhdb,p_nh_ecmp_param);
    }
    /*Only replace member can exceed  MCHIP_CAP(SYS_CAP_NH_MAX_ECPN) member  */
    if(p_nhdb->mem_num > MCHIP_CAP(SYS_CAP_NH_MAX_ECPN)  || p_nhdb->mem_num > SYS_USW_MAX_ECPN)
    {
        return CTC_E_INVALID_CONFIG;
    }

   sal_memcpy(&ecmp_param  , p_nh_ecmp_param,sizeof(ctc_nh_ecmp_nh_param_t));
    for (loop = 0; loop < p_nh_ecmp_param->nh_num; loop++)
    {
        ecmp_param.nh_num = 1;
        ecmp_param.nhid[0] = p_nh_ecmp_param->nhid[loop];
        ret = _sys_usw_nh_update_ecmp_cb( lchip,  p_nhdb,  &ecmp_param);
        if (ret && (p_nh_ecmp_param->upd_type == CTC_NH_ECMP_ADD_MEMBER))
        {
            goto roll_back;
        }
    }
    return ret;

roll_back:
    while(loop)
    {
        ecmp_param.upd_type = CTC_NH_ECMP_REMOVE_MEMBER;
        ecmp_param.nh_num = 1;
        ecmp_param.nhid[0] = p_nh_ecmp_param->nhid[loop-1];
        _sys_usw_nh_update_ecmp_cb( lchip,  p_nhdb,  &ecmp_param);
		loop--;
    };

    return ret;
}
int32
sys_usw_nh_delete_ecmp_cb(uint8 lchip, sys_nh_info_com_t* p_com_db, sys_nh_param_com_t* p_com_nh_param)
{
    sys_nh_info_ecmp_t* p_nhdb = NULL;
    uint16 loop = 0;
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_usw_opf_t opf;
    sys_nh_ref_list_node_t* p_ref_node = NULL;
    sys_nh_ref_list_node_t* p_tmp_node = NULL;
    uint16 member_cnt = 0;
    void* p_tmp_nh_info = NULL;
	uint8 freed =0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    sal_memset(&opf, 0, sizeof(opf));

    p_nhdb = (sys_nh_info_ecmp_t*)(p_com_db);
    member_cnt = p_nhdb->ecmp_cnt ;
    //p_nhdb->ecmp_cnt = 0;

    CTC_ERROR_RETURN(_sys_usw_nh_enable_spray_ecmp(lchip,p_nhdb->type,0));
    if (p_nhdb->h_ecmp_en && DRV_IS_TSINGMA(lchip))
    {
        for (loop = 0; loop < member_cnt; loop++)
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nhdb->nh_array[loop], (sys_nh_info_com_t**)&p_nh_info));
            if (p_nh_info)
            {
                p_nhdb->nh_array[loop] = 0;
                sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info);
            }
        }

        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_group_opf_type;
        opf.pool_index = 0;
        opf.reverse    = 1;
        sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, g_usw_nh_master[lchip]->hecmp_mem_num, p_nhdb->ecmp_group_id);
        mem_free(p_nhdb->nh_array);
        return CTC_E_NONE;
    }
    else if (p_nhdb->type != CTC_NH_ECMP_TYPE_XERSPAN )
    {
        if (DRV_IS_TSINGMA(lchip))
        {
            _sys_usw_nh_update_hecmp_member(lchip, p_com_db->hdr.nh_id, 1);
			freed = 1;
        }
        else if(DRV_FROM_TMM(lchip) && p_com_nh_param->hdr.p_nh_info_ext)
        {
            sys_usw_nh_update_ecmp_member(lchip, p_com_db->hdr.nh_id, SYS_NH_CHANGE_TYPE_NH_DELETE, p_com_nh_param->hdr.p_nh_info_ext->ecmp_list);
        }

        if (p_nhdb->stats_valid)
        {
            sys_stats_param_t sts_param;
            sal_memset(&sts_param, 0, sizeof(sts_param));
            sts_param.ptr = p_nhdb->ecmp_group_id;
            sts_param.type = (p_nhdb->h_ecmp_en && DRV_FROM_AT(lchip)) ? SYS_STATS_TYPE_HECMP : SYS_STATS_TYPE_ECMP;
            sys_usw_flow_stats_free_statsptr(lchip, &sts_param);
        }

        p_nhdb->valid_cnt = 0;
        p_nhdb->type = CTC_NH_ECMP_TYPE_STATIC;
        sys_usw_nh_update_ecmp_group(lchip, p_nhdb, 0);

        /* free ecmp groupId ? */
        opf.pool_type = g_usw_nh_master[lchip]->ecmp_group_opf_type;
        opf.pool_index =  (g_usw_nh_master[lchip]->h_ecmp_en && p_nhdb->h_ecmp_en)?1:0;

        sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, 1, (uint32)(p_nhdb->ecmp_group_id));
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " INFO: free ecmp_group_id:%d\n", p_nhdb->ecmp_group_id);

        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
        opf.pool_index = p_nhdb->h_ecmp_en ?1:0;
        opf.reverse    = 0;

       if(p_nhdb->mem_num) sys_usw_opf_free_offset(lchip, &opf, p_nhdb->mem_num, (uint32)p_nhdb->ecmp_member_base);
    }
    else
    {
        uint8 hash_num = 16;
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_8W, 1, p_nhdb->hdr.dsnh_offset);

        /*1. Free new dsl3edit  entry*/
        sys_usw_nh_offset_free(lchip,
                                                       SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6 + SYS_NH_TYPE_STEP_TO_INNER, hash_num,
                                                       p_nhdb->l3edit_offset_base);

        if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))
        {

            /*1. Free new dsl2edit  entry*/
            sys_usw_nh_offset_free(lchip,
                                                           SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, hash_num*2,
                                                           p_nhdb->l2edit_offset_base);
        }

    }

    for (loop = 0; loop < member_cnt; loop++)
    {
        if (p_nhdb->mem_is_tunnel)
        {
            p_tmp_nh_info = (void*)_sys_usw_nh_lkup_srh_id(lchip, p_nhdb->nh_array[loop]);
        }
        else
        {
            CTC_ERROR_DUMP(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nhdb->nh_array[loop], (sys_nh_info_com_t**)&p_tmp_nh_info));
        }
        if (p_tmp_nh_info)
        {
            p_nhdb->nh_array[loop] = 0;
            CTC_ERROR_DUMP(sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_tmp_nh_info));
        }
    }

    if (p_nhdb->ant_flow_en)
    {
        sys_usw_ftm_free_table_offset(lchip, DsAntFlowEcmp_t, 0, SYS_ECMP_SPM_ENTRY_NUM, (p_nhdb->ant_flow_base << SYS_ECMP_SPM_TBL_BASE_WIDTH));
        _sys_usw_nh_ecmp_clear_ant_flow(lchip, p_nhdb, 0, 1);
    }

    mem_free(p_nhdb->nh_array);

    /*Delete ecmp  list */
    if (!freed && p_com_nh_param->hdr.p_nh_info_ext)
    {
        p_ref_node = p_com_nh_param->hdr.p_nh_info_ext->ecmp_list;
        while (p_ref_node)
        {
            /*Remove from db*/
            p_tmp_node = p_ref_node;
            p_ref_node = p_ref_node->p_next;
            mem_free(p_tmp_node);
        }
    }

    if (p_nhdb->rpf_en)
    {
        sys_rpf_info_t rpf_info;
        sal_memset(&rpf_info, 0, sizeof(rpf_info));
        rpf_info.rpf_id = p_nhdb->rpf_id;
        rpf_info.nh_rpf = 1;
        sys_usw_rpf_remove_profile(lchip, &rpf_info);
    }
    return CTC_E_NONE;
}


int32
sys_usw_nh_create_rspan_ecmp(uint8 lchip, sys_nh_param_com_t* p_com_nh_para,
                                  sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_ecmp_t* p_nh_param = NULL;
    sys_nh_info_ecmp_t* p_nhdb = NULL;
    uint8 hash_num = 0;
    uint32 nhid = 0;
    sys_nh_info_ip_tunnel_t* p_tunnel_nhdb = NULL;
    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_param_dsnh_t dsnh_param;
    ctc_nh_ecmp_nh_param_t ecmp_nh_param;
    sys_nh_param_ecmp_t sys_ecmp;
    uint8 index = 0;
    int32 ret = 0;
    uint8 sub_index = 0;
    uint16  nh_array_size = 0;
    uint32 dsnh_offset = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    /* 1. sanity check & init */
    p_nh_param = (sys_nh_param_ecmp_t*)p_com_nh_para;
    p_nhdb = (sys_nh_info_ecmp_t*)p_com_db;
    CTC_PTR_VALID_CHECK(p_nh_param->p_ecmp_param);
    sal_memset(&dsnh_param, 0, sizeof(sys_nh_param_dsnh_t));
    if (CTC_FLAG_ISSET(p_nh_param->p_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP) || CTC_FLAG_ISSET(p_nh_param->p_ecmp_param->flag, CTC_NH_ECMP_FLAG_RPF_PROFILE_EN))
    {
        return CTC_E_INVALID_PARAM;
    }

    p_nhdb->type = CTC_NH_ECMP_TYPE_XERSPAN;

    hash_num = 16;
    CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_8W, 1, &dsnh_offset));
    p_nhdb->hdr.dsnh_offset = dsnh_offset;

    dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_XERSPAN;
    dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
    p_nhdb->hdr.nh_entry_type = SYS_NH_TYPE_ECMP;

    nhid =  p_nh_param->p_ecmp_param->nhid[0];
    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_info), ret, error1);
    if (SYS_NH_TYPE_IP_TUNNEL != p_nh_info->hdr.nh_entry_type)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Need tunnel nexthop for member \n");
        ret = CTC_E_INVALID_CONFIG;
        goto error1;
    }

    p_tunnel_nhdb = (sys_nh_info_ip_tunnel_t *)p_nh_info;

    if (CTC_FLAG_ISSET(p_tunnel_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Current nexthop is unresolved nexthop \n");
        ret = CTC_E_INVALID_CONFIG;
        goto error1;
    }

    /*1. Allocate new dsl3edit mpls entry*/
    CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip,
                                                    SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6 + SYS_NH_TYPE_STEP_TO_INNER, hash_num,
                                                    &dsnh_param.l3edit_ptr), ret, error1);
    p_nhdb->l3edit_offset_base = dsnh_param.l3edit_ptr;


    if (CTC_FLAG_ISSET(p_tunnel_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))
    {

        /*1. Allocate new dsl2edit mpls entry*/
        CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip,
                                                        SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, hash_num*2,
                                                        &dsnh_param.l2edit_ptr), ret, error2);
        p_nhdb->l2edit_offset_base = dsnh_param.l2edit_ptr;
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);
    }


    dsnh_param.hash_num = 0;
    dsnh_param.dest_vlan_ptr = p_tunnel_nhdb->dest_vlan_ptr;
    dsnh_param.span_id = p_tunnel_nhdb->span_id;
    p_nhdb->gport = p_tunnel_nhdb->gport;
    p_nhdb->mem_num = hash_num;
    if (CTC_FLAG_ISSET(p_tunnel_nhdb->flag, SYS_NH_IP_TUNNEL_KEEP_IGS_TS))
    {
        CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_ERSPAN_KEEP_IGS_TS);
    }

    CTC_ERROR_GOTO(sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param), ret, error3);

    nh_array_size = (p_nh_param->p_ecmp_param->nh_num + SYS_ECMP_ALLOC_MEM_STEP - 1) / SYS_ECMP_ALLOC_MEM_STEP;
    nh_array_size = nh_array_size * SYS_ECMP_ALLOC_MEM_STEP;
    p_nhdb->nh_array = mem_malloc(MEM_NEXTHOP_MODULE,  nh_array_size * sizeof(uint32));
    if (NULL == p_nhdb->nh_array)
    {
        ret = CTC_E_NO_MEMORY;
        goto error3;
    }

    sal_memcpy(&ecmp_nh_param, p_nh_param->p_ecmp_param, sizeof(ctc_nh_ecmp_nh_param_t));
    sal_memcpy(&(sys_ecmp.hdr), &(p_nh_param->hdr), sizeof(sys_nh_param_hdr_t));
    for (index = 0; index < p_nh_param->p_ecmp_param->nh_num; index++)
    {
        ecmp_nh_param.nh_num = 1;
        ecmp_nh_param.nhid[0] = p_nh_param->p_ecmp_param->nhid[index];
        sys_ecmp.p_ecmp_param = &ecmp_nh_param;
        ret = sys_usw_nh_update_ecmp_cb(lchip, p_com_db, (sys_nh_param_com_t*)&sys_ecmp );
        if (ret < 0)
        {
            for (sub_index = 0; sub_index < index; sub_index++)
            {
                /*rollback already add nhid member*/
                CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nh_param->p_ecmp_param->nhid[sub_index], (sys_nh_info_com_t**)&p_nh_info));
				p_nhdb->nh_array[sub_index] = 0;
                sys_usw_nh_ecmp_del_ref_list(lchip, p_nhdb, p_nh_info);
            }
            goto error4;
        }
    }
    return CTC_E_NONE;
error4:
    if (p_nhdb->nh_array)
    {
        mem_free(p_nhdb->nh_array);
    }
error3:
    if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))
    {
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, 16*2, p_nhdb->l2edit_offset_base);
    }
error2:
    sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6 + SYS_NH_TYPE_STEP_TO_INNER, 16, p_nhdb->l3edit_offset_base);
error1:
    sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_8W, 1, p_nhdb->hdr.dsnh_offset);
    return ret;
}



int32
sys_usw_nh_create_ecmp_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_param, sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_ecmp_t* p_nh_param = NULL;
    ctc_nh_ecmp_nh_param_t* p_nh_ecmp_param = NULL;

    p_nh_param = (sys_nh_param_ecmp_t*)(p_com_nh_param);

    p_nh_ecmp_param = p_nh_param->p_ecmp_param;

    if (p_nh_ecmp_param->type != CTC_NH_ECMP_TYPE_XERSPAN)
    {
        CTC_ERROR_RETURN(sys_usw_nh_create_normal_ecmp(lchip, p_com_nh_param, p_com_db));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_create_rspan_ecmp(lchip, p_com_nh_param, p_com_db));
    }

    return CTC_E_NONE;
}


int32
sys_usw_nh_wb_restore_ecmp_nhinfo(uint8 lchip,  sys_nh_info_com_t* p_nh_info_com, sys_wb_nh_info_ecmp_t *p_wb_nh_info)

{
    sys_nh_info_ecmp_t  *p_nh_info = (sys_nh_info_ecmp_t  *)p_nh_info_com;
    uint16 nh_array_size = 0;

    p_nh_info->ecmp_cnt = (p_wb_nh_info->ecmp_cnt == CTC_MAX_UINT8_VALUE) ? CTC_CONST256 : p_wb_nh_info->ecmp_cnt;
    p_nh_info->valid_cnt = (p_wb_nh_info->valid_cnt == CTC_MAX_UINT8_VALUE) ? CTC_CONST256 : p_wb_nh_info->valid_cnt;
    p_nh_info->type = p_wb_nh_info->type;
    p_nh_info->failover_en = p_wb_nh_info->failover_en;
    p_nh_info->mem_num = (p_wb_nh_info->mem_num == CTC_MAX_UINT8_VALUE) ? CTC_CONST256 : p_wb_nh_info->mem_num;
    p_nh_info->ecmp_group_id = p_wb_nh_info->ecmp_group_id ;
    p_nh_info->random_rr_en = p_wb_nh_info->random_rr_en ;
    p_nh_info->stats_valid =  p_wb_nh_info->stats_valid;
    p_nh_info->gport = p_wb_nh_info->gport ;
    p_nh_info->ecmp_member_base = p_wb_nh_info->ecmp_member_base;
    p_nh_info->l3edit_offset_base = p_wb_nh_info->l3edit_offset_base ;
    p_nh_info->l2edit_offset_base = p_wb_nh_info->l2edit_offset_base;
    p_nh_info->h_ecmp_en = p_wb_nh_info->hecmp_en;
    p_nh_info->ant_flow_base = p_wb_nh_info->ant_flow_base;
    p_nh_info->ant_flow_en = p_wb_nh_info->ant_flow_en;
    p_nh_info->rpf_id = p_wb_nh_info->rpf_id;
    p_nh_info->rpf_en = p_wb_nh_info->rpf_id?1:0;
    if (p_wb_nh_info->type == CTC_NH_ECMP_TYPE_DLB)
    {
        g_usw_nh_master[lchip]->ecmp_spray_ref --;
    }
    else if(p_wb_nh_info->type == CTC_NH_ECMP_TYPE_SPRAY)
    {
        g_usw_nh_master[lchip]->ecmp_spray_ref ++;
    }
    p_nh_info->mem_is_tunnel = p_wb_nh_info->mem_is_tunnel;
    p_nh_info->tunnel_is_ldp = p_wb_nh_info->tunnel_is_ldp;
    p_nh_info->srh_replace_ipda = p_wb_nh_info->srh_replace_ipda;
    if(p_nh_info->ant_flow_en)
    {
        CTC_ERROR_RETURN(sys_usw_ftm_alloc_table_offset_from_position(lchip, DsAntFlowEcmp_t, 0, SYS_ECMP_SPM_ENTRY_NUM, p_nh_info->ant_flow_base<< SYS_ECMP_SPM_TBL_BASE_WIDTH));
    }
    if (p_nh_info->ecmp_cnt)
    {
         nh_array_size = (p_nh_info->ecmp_cnt + SYS_ECMP_ALLOC_MEM_STEP - 1) / SYS_ECMP_ALLOC_MEM_STEP;
         nh_array_size = nh_array_size * SYS_ECMP_ALLOC_MEM_STEP;
         p_nh_info->nh_array = mem_malloc(MEM_NEXTHOP_MODULE, nh_array_size * sizeof(uint32));
        if (NULL == p_nh_info->nh_array)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(&p_nh_info->nh_array[0], 0, p_nh_info->ecmp_cnt*sizeof(uint32));
    }

    if (p_nh_info->type == CTC_NH_ECMP_TYPE_XERSPAN )
    {
        uint8 hash_num = 16;

        sys_usw_nh_offset_alloc_from_position(lchip,
                                                     SYS_NH_ENTRY_TYPE_NEXTHOP_8W, 1,
                                                     p_nh_info->hdr.dsnh_offset);

        sys_usw_nh_offset_alloc_from_position(lchip,
                                                     SYS_NH_ENTRY_TYPE_L3EDIT_TUNNEL_V6 + SYS_NH_TYPE_STEP_TO_INNER, hash_num,
                                                     p_nh_info->l3edit_offset_base);

        if (CTC_FLAG_ISSET(p_wb_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))
        {


            sys_usw_nh_offset_alloc_from_position(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W,
                                                         hash_num * 2, p_nh_info->l2edit_offset_base);

        }
    }
    else
    {
        sys_usw_opf_t opf;

         sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_group_opf_type;
        opf.pool_index =  (g_usw_nh_master[lchip]->h_ecmp_en && p_nh_info->h_ecmp_en && DRV_FROM_TMM(lchip))?1:0;
        opf.reverse = ((CTC_NH_ECMP_TYPE_RR == p_nh_info->type) || (CTC_NH_ECMP_TYPE_RANDOM_RR == p_nh_info->type)) ? 0 : 1;

        CTC_ERROR_RETURN(sys_usw_opf_alloc_offset_from_position(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, (p_nh_info->h_ecmp_en && DRV_IS_TSINGMA(lchip))?g_usw_nh_master[lchip]->hecmp_mem_num:1, p_nh_info->ecmp_group_id));
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type  = g_usw_nh_master[lchip]->ecmp_member_opf_type;
        opf.pool_index = p_nh_info->h_ecmp_en ?1:0;
        opf.multiple = SYS_ECMP_MEM_HW_SUB_NUM;

        if (p_nh_info->mem_num && (!p_nh_info->h_ecmp_en || DRV_FROM_TMM(lchip)))
        {
            CTC_ERROR_RETURN(sys_usw_opf_alloc_offset_from_position(lchip, &opf, p_nh_info->mem_num, p_nh_info->ecmp_member_base));
        }
    }
    if (p_nh_info->rpf_en)
    {
         sys_usw_rpf_restore_index(lchip, p_nh_info->rpf_id);
    }

     return CTC_E_NONE;
}

/**
 @brief Callback function used to get ipuc nexthop
 */
int32
sys_usw_nh_get_ecmp_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db, void* p_para)
{
    sys_nh_info_ecmp_t* p_nh_info;
    ctc_nh_ecmp_nh_param_t* p_ecmp_param = NULL;
    uint16 index = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_PTR_VALID_CHECK(p_para);

    p_nh_info = (sys_nh_info_ecmp_t*)(p_nh_db);
    p_ecmp_param = (ctc_nh_ecmp_nh_param_t*)p_para;
    p_ecmp_param->failover_en = p_nh_info->failover_en;
    p_ecmp_param->type = p_nh_info->type;
    p_ecmp_param->member_num = p_nh_info->mem_num;
    p_ecmp_param->nh_num = p_nh_info->ecmp_cnt;
    if (p_nh_info->h_ecmp_en)
    {
        CTC_SET_FLAG(p_ecmp_param->flag, CTC_NH_ECMP_FLAG_HECMP);
    }
    if (p_nh_info->ant_flow_en)
    {
        CTC_SET_FLAG(p_ecmp_param->flag, CTC_NH_ECMP_FLAG_SPM_EN);
    }
    if (p_nh_info->mem_is_tunnel)
    {
        CTC_SET_FLAG(p_ecmp_param->flag, CTC_NH_ECMP_FLAG_MEM_IS_SRH);
    }
    if (p_nh_info->rpf_en)
    {
        CTC_SET_FLAG(p_ecmp_param->flag, CTC_NH_ECMP_FLAG_RPF_PROFILE_EN);
    }
    for (index = 0; index < p_ecmp_param->nh_num; index++)
    {
       p_ecmp_param->nhid[index] =  p_nh_info->nh_array[index];
    }

    sys_usw_flow_stats_lookup_statsid(lchip, p_nh_info->h_ecmp_en? CTC_STATS_STATSID_TYPE_HECMP : CTC_STATS_STATSID_TYPE_ECMP, p_nh_info->ecmp_group_id, &p_ecmp_param->stats_id, CTC_INGRESS);

    return CTC_E_NONE;
}

